Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You can write an iterator yourself, no need to leave ?pairs idiom:

  function sortpairs(t)
    local keys = { }
    for key in pairs(t) do
      table.insert(keys, key)
    end
    table.sort(keys, function (a, b)
      return tostring(a) < tostring(b)
    end)
    local i = 1
    return function (t)
      local key = keys[i]
      i = i + 1
      if key ~= nil then
        return key, t[key], i-1
      end
    end, t
  end

  t = {a=10, c=20, d=30, b=40, 50}
  for k,v,i in sortpairs(t) do
    print(k, v, i)
  end


What Lua is lacking here (and why the above iterator function needs 17 lines) is the ability to have “for” go through a list (without converting the list in to values returned by an iterator function), which would let us quickly and easily sort lists that “for” can use. Something like:

  d = {"foo": 2, "bar": 1, "zoo": 4}
  for k in sorted(d.keys()):
    print k
(I’m not advocating Python here, since Perl has a similar way of using “for” to go through lists which can also be easily sorted)

However, with Lua, “for” only accepts a numeric range, or an iterator function, so customizing “for” requires understanding function closures: Understanding how a function, when called multiple times, stores variables altered in previous invocations of the function, and understanding how to give those variables initial values (usually in the “function factory” function which creates the function we use).

In other words, “for”, in most modern high-level languages, can be one of:

1. for variable in [something that specifies a numeric range]

2. for variable in [iterator function]

3. for variable in [list]

But Lua only has “something that specifies a numeric range” and “iterator function”; it can not natively go through a list.


You can convert a list first and then feed it to a simple iterator. I don’t fully understand what your exact real-code issues can be, but hope this snippet may help:

  function vs(t)
    local i = 0
    return function (t)
      i = i + 1
      return t[i]
    end, t
  end

  function sorted(t, cmp)
    table.sort(t, cmp or function (a, b)
      return tostring(a) < tostring(b)
    end)
    return t
  end

  function keys(t)
    local keys = { }
    for key in pairs(t) do
      table.insert(keys, key)
    end
    return keys
  end

  t = {a=10, c=20, d=30, b=40, 50}
  for k in vs(sorted(keys(t))) do
    print(k, t[k])
  end
I.e. if “natively” means strictly “for in t” that generates values, then no, Lua can’t do that. But if “for in vs(t)” is okay, then that vs() is the solution.


That looks good, and I think putting these in a prominent place of the Lua documentation (along with a notice that the code is public domain) would help us who are used to the AWK/Perl/Python/PHP way of having “for” natively traverse a list without needing a complicated list-to-iterator function that uses function closure (i.e. the iterator function remembers the value “i” -- I’m writing this for the lurkers because code like this can be difficult to follow).

One honest question: Is there any reason why the function factory (i.e. a function which returns a function) which converts a list (Actually, table with ascending integer indexes) in to an iterator Lua can use with “for” returns both the element and the entire table here? Here is the code I am asking about:

    return function (t)
      i = i + 1
      return t[i]
    end, t
I’m curious why we’re returning both the table element for the iterator and the entire table.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: