tags:

views:

1225

answers:

2

What's the most efficient way to determine if a table is empty (that is, currently contains neither array-style values nor dict-style values)?

Currently, I'm using next():

if not next(myTable) then
    -- Table is empty
end

Is there a more efficient way?

Note: The # operator does not suffice here, as it only operates on the array-style values in the table - thus #{test=2} is indistinguishable from #{} because both return 0. Also note that checking if the table variable is nil does not suffice as I am not looking for nil values, but rather tables with 0 entries (i.e. {}).

A: 

One possibility would be to count the number of elements, by using the metatable "newindex" key. When assigning something not nil, increment the counter (the counter could live in the metatable as well) and when assigning nil, decrement the counter.

Testing for empty table would be to test the counter with 0.

Here's a pointer to metatable documentation

I do like your solution though, and I honestly can't assume that my solution is faster overall.

0x6adb015
The original question is not about counting just "array" entries.
lhf
0x6's suggestion isn't specific to array-style entries (newindex works for both numerical and non-numerical indices). However, the main issue would be detecting when `nil` is assigned, since __newindex does not trigger if the key already exists in the table.
Amber
For this trick to work, the metatable would have to implement both `__index` and `__newindex`, storing the actual data in a shadow table and keeping the real table empty so that `__index` will be invoked at all. Thinking out loud, I suspect that the raised cost of every single lookup can't be worth it.
RBerteig
+4  A: 

Your code is efficient but wrong. (Consider {[false]=0}.) The correct code is

if next(myTable) == nil then
   -- myTable is empty
end

For maximum efficiency you'll want to bind next to a local variable, e.g.,

...
local next = next 
...
... if next(...) ...
Norman Ramsey
Good point on the technical correctness; in the particular cases I've been utilizing the original code, `false` wouldn't be an expected key so the `if not` worked fine, but I'll probably make a habit of comparing to `nil` instead in the future, just as a good habit. And yes, I've been binding common utility functions to local vars for speed. Thanks for the input though.
Amber