192

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?

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • 5
    @lhf: I have written a serializer which remembers every object it has seen, and the next time it sees it it emits an integer reference instead of the object. The natural way to write this is something like `dictionary[value] = #dictionary + 1`, where `#` represents the number of _all_ objects. What _I_ wonder is why you _don't_ want this: in all _sane_ use cases for # (see answer by kaizer.se), the count of all objects is exactly equal to what # already returns; it seems like making # count everything is strictly an improvement. Of course I'm a Lua newbie and might be missing the point. – Roman Starkov Apr 25 '10 at 09:40
  • @lhf Another use example: retrieve a lot of data into a table, where each data item has a unique string identifier. I use this identifier as the key because I'll be looking up by it later on. I now want to print the number of data items processed. I have to keep a counter and manually increment it for every row. Certainly not a big deal, but it is unusual not to be able to tell something like this without counting, and since you asked "why"... :) – Roman Starkov Apr 26 '10 at 00:33
  • 1
    The table is the best place to keep the information about the current object count, when used as container. For example when the table is used as a Set. – u0b34a0f6ae Apr 26 '10 at 22:53
  • @lhf: I've also got a use case where I need to know the number, in this case I need to know if there's only one item left in a table, in which case I handle it differently to if there are many items. If the answer is that we count them that's fine though; I'd guess a function that just had the answer would cost us performance elsewhere (such a feature would probably require lua to test the new and old value for nil every time we set a table value and then update a counter accordingly) – Alternator Nov 03 '14 at 20:05
  • @Alternator, to test whether there is exactly one pair in a table, use `next(t)~=nil and next(next(t))==nil`. – lhf Nov 04 '14 at 09:28
  • 1
    Remark, it appears that the table doesn't really store the number of hash items (from the source code https://www.lua.org/source/5.3/ltable.c.html#luaH_newkey , https://www.lua.org/source/5.3/ltable.c.html#numusehash), so asymptotically speaking looping over the keys is the fastest way. – user202729 Jul 08 '22 at 06:09

10 Answers10

178

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.

u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
  • Well, he said "without counting them", but it's possible there is no other way – Michael Mrozek Apr 24 '10 at 19:16
  • 29
    `According to the manual, any of 3, 5 and 9 are valid results for #t`. According to the manual, calling # on non-sequences is *[undefined](http://www.lua.org/manual/5.2/manual.html#3.4.6)*. That means that *any* result (-1, 3, 3.14, 5, 9) is valid. – cubuspl42 May 12 '14 at 20:08
  • 15
    Regarding valid results: u0b34a0f6ae is correct for Lua 5.1, while cubuspl42 is correct for Lua 5.2. In either case, the whole thing is completely insane. – Jeremy Apr 17 '15 at 16:37
  • It's better to have a basic fp utility based on reduce: https://github.com/sarimarton/.config/blob/master/hammerspoon/util/fp.lua#L33 – sarimarton Jun 14 '20 at 12:15
  • @sarimarton And what are we supposed to do with this comment now that you've made that repo private / deleted it? – FeRD Nov 14 '22 at 00:25
  • 1
    @FeRD sorry - https://gist.github.com/sarimarton/fc02d27fa7c06d296d99f858b1143e5a – sarimarton Nov 15 '22 at 08:25
  • @sarimarton Uh... wow, that's the first time that's ever actually worked to get the information back. I don't even know how to react to that. ‍ I guess, thanks! – FeRD Nov 16 '22 at 13:56
  • This does not work for tables with keys which have a value of `nil`, e.g. `t = { a=nil, b=nil, c=nil }`, it will return 0 – rboy May 17 '23 at 21:11
  • 1
    @rboy true but the point is, in Lua assigning `nil` to a table key means deleting it. There's no way to distinguish between keys with `nil` values and keys with no value, regardless of method. – Noam Jun 12 '23 at 19:23
26

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
  • 47,835
  • 5
  • 49
  • 70
  • Is there a convenient way to handle erasing entries with this method? – u0b34a0f6ae Apr 25 '10 at 20:13
  • 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 Apr 26 '10 at 04:43
  • 2
    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 Apr 26 '10 at 19:27
  • @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. – u0b34a0f6ae Apr 26 '10 at 22:51
  • 1
    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 Apr 26 '10 at 23:17
12

The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:

tbl={
    [1]
    [2]
    [3]
    [4]
    [5]
}
print(#tbl)--prints the highest number in the table: 5

Sadly, if they are not numbered, it won't work.

Surge12
  • 165
  • 2
  • 9
9

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.

kikito
  • 51,734
  • 32
  • 149
  • 189
  • 5
    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 Apr 26 '10 at 22:32
  • 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. – Roman Starkov Apr 27 '10 at 10:43
  • Counting is the only way for tables, and adding a lines when creating the tables is better than a function to count them every time you need the count. You can add a key at the end with the value set to the count. – Henrik Erlandsson Jul 30 '14 at 13:46
6
function GetTableLng(tbl)
  local getN = 0
  for n in pairs(tbl) do 
    getN = getN + 1 
  end
  return getN
end

You're right. There are no other way to get length of table

스피겔 빈
  • 61
  • 1
  • 2
4

You could use penlight library. This has a function size which gives the actual size of the table.

It has implemented many of the function that we may need while programming and missing in Lua.

Here is the sample for using it.

> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3 
> a['blah'] = 24

> #a
0

> tablex.size(a)
3
  • 1
    Yeah but all that does is `for k in pairs(t) do i = i + 1 end` so it's no better than other options on this topic already and adds extra overhead of using another lib – Stephen York May 10 '21 at 06:53
1
local function CountedTable(x)
    assert(type(x) == 'table', 'bad parameter #1: must be table')

    local new_t = {}
    local mt = {}

    -- `all` will represent the number of both
    local all = 0
    for k, v in pairs(x) do
        all = all + 1
    end

    mt.__newindex = function(t, k, v)
        if v == nil then
            if rawget(x, k) ~= nil then
                all = all - 1
            end
        else
            if rawget(x, k) == nil then
                all = all + 1
            end
        end

        rawset(x, k, v)
    end

    mt.__index = function(t, k)
        if k == 'totalCount' then return all
        else return rawget(x, k) end
    end

    return setmetatable(new_t, mt)
end

local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }

assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
Sleepwom
  • 227
  • 6
  • 15
  • `__newindex` only call when a new key define, so there are no chance to call `__newindex` when we set `nil` to a exists key. – Frank AK Jun 06 '18 at 07:30
0

I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.

So subtract 1 from the index that returned a nil, and that's the size of the table.

I have a global Variable for TableSize that is set to the result of this count.

function Check_Table_Size()
  local Count = 1
  local CurrentVal = (CueNames[tonumber(Count)])
  local repeating = true
  print(Count)
  while repeating == true do
    if CurrentVal ~= nil then
      Count = Count + 1
      CurrentVal = CueNames[tonumber(Count)]
     else
      repeating = false
      TableSize = Count - 1
    end
  end
  print(TableSize)
end
0

Found some solution that works fine for me.

local someTable = {3, 4, 5}
local table_size = #someTable
print("The table has [" .. table_size .. "] items")
SkyDancer
  • 129
  • 1
  • 4
  • 13
-1

seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements

mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))

It will print 2 correctly

Yongxin Zhang
  • 87
  • 1
  • 3
  • This is wrong... as mentioned in the answers above `getn` or `#` only counts the integer indices and they only works when the indices are consecutive – user202729 Jul 08 '22 at 06:12
  • `table.insert` also isn't special, except that you're letting it create numerically-indexed entries in the table. You could replace those two `table.insert` calls with `mytable[1] = element1` and `mytable[2] = element2` and the result of this code would be exactly the same. Which is why `table.getn(mytable)` returns 2. – FeRD Nov 14 '22 at 00:38