Most efficient way to determine if a Lua table is empty (contains no entries)?

Viewed 97661

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. {}).

8 Answers

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(...) ...

(When next is local, the code finds primitive function next by a constant-time indexing operation into an array of "upvalues." When next is left global, finding next involves indexing index the "environment" hash table, which contains the values of the global variables. This indexing operation is still constant-time, but it is significantly slower than the array lookup for a local variable.)

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.

better to avoid the evaluation of __eq if overloaded.

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

or

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

This is probably what you wanted:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a = { }
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

Output:

true
false
true

try serpent, work for me

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, {comment=false})
end

myTable = {}

if type(myTable) == 'table' and vtext(myTable) == '{}' then
   -- myTable is empty
end

How about this ?

if endmyTable[1] == nil then
  -- myTable is empty
end
Related