tags:

views:

147

answers:

3

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:

tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl))   -- prints "1     1"

count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count)            -- prints "2"

How do I get the number of all entries without counting them?

+2  A: 

You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:

t = {1,2,3}
t[5] = 1
t[9] = 1

According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.

kaizer.se
Well, he said "without counting them", but it's possible there is no other way
Michael Mrozek
+3  A: 

You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.

ergosys
Is there a convenient way to handle erasing entries with this method?
kaizer.se
Sadly, it appears the __newindex function doesn't fire on nil assignments unless the index doesn't exist, so it seems you'd have to funnel entry removal through a special function.
ergosys
You should store data in a separate table (for example accessible as upvalue for __index and __newindex). Then both __index and __newindex would fire for each table access. You should check if the performance is acceptable though.
Alexander Gladysh
@Alexander: Ah yes, and then the next stumbling point: if you proxy the table, then the normal iteration by pairs doesn't work. This will be possible to solve in Lua 5.2, I heard.
kaizer.se
There would be __pairs and __ipairs metamethods in 5.2... If you want to do it in 5.1, you'd have to replace pairs() function with your own. But that's probably too much. :-)
Alexander Gladysh
+1  A: 

There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.

count = 0
tbl = {}

tbl["test"] = 47
count = count + 1

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

There's no other way, the # operator will only work on array-like tables with consecutive keys.

egarcia
This can be automated with a proxy table and metamethods, as mentioned by [ergosys's answer](http://stackoverflow.com/questions/2705793/how-to-get-number-of-entries-in-a-lua-table/2705855#2705855)
RBerteig
I got the impression from the comments that the proxytable/metamethods thing doesn't fully support this scenario yet, so I'll accept this as the best way currently available.
romkyns