1

Given a table with mixed indexes like:

table = {
  foo = 'bar'
  [1] = 'foobar'
}

My question is about the # which gives the last index which is not separate through a gap while iterating through the table.

print(#table) 

will give the output 1.

table = {
  foo = 'bar',
  lol = 'rofl',
  [1] = 'some',
  [2] = 'thing',
  [3] = 'anything',
  [4] = 'else'
}
print(#table)

should print 4

Can I be 100% sure that the # will never be distracted by non-numeral indexes? Are those indexes really unregarded at every time?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
jawo
  • 856
  • 1
  • 8
  • 24
  • Although it's easy to understand what you mean, it's better to make your example code compilable. Your table constructor like `4 = else` is obviously illegal. – Yu Hao Oct 28 '14 at 12:37
  • Okay, done. Didn't noticed while typing. – jawo Oct 28 '14 at 12:41
  • Allow me to eidt your code, it's more than `else` beging a keyword. `[4] = 'else'` looks a little less clear and unlike the more common syntax sugar, but it's legal. – Yu Hao Oct 28 '14 at 12:48

3 Answers3

3

Yes, you can count on that (in lua 5.1).

From the lua reference manual:

The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).

lua 5.2 allows for the __len metamethod to operate on tables and that means # can do other things. See @kikito's answer for some examples.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
2

Etan answer is correct, but not complete.

In Lua, if a table's metatable has a __len function, it will control what the # operator spits out. One can define it so that it takes into account the non-array keys.

local mt = {__len = function(tbl)
  local len = 0
  for _ in pairs(tbl) do len = len + 1 end
  return len
end}

This demonstrates the thing:

local t = {1,2,3,4,foo='bar',baz='qux'}

print(#t) -- 4
setmetatable(t, mt)
print(#t) -- 6

If you really want to make sure that you get the "proper" array-like length, you must use rawlen instead:

print(rawlen(t)) -- 4, even with the metatable set

Edit: Note that __len does not work as I mention on Lua 5.1

kikito
  • 51,734
  • 32
  • 149
  • 189
  • And again, thank you for the guide but it doesn't fit the question. – jawo Oct 28 '14 at 15:36
  • The [Lua 5.1 reference manual](http://www.lua.org/manual/5.1/manual.html#2.8) always said, that the `__len` metamethod does not work on tables (or strings) ... – siffiejoe Oct 28 '14 at 15:41
  • 2
    @Sempie: In the question you ask "Can I be 100% sure that the # will *never* be distracted by non-numeral indexes?". The answer to that "absolute never" is no (metamethods can change it). I think it is pertinent. – kikito Oct 28 '14 at 17:31
  • Indeed, lua 5.2 changes the behaviour of `#` a bit in a way that is relevant here. – Etan Reisner Oct 28 '14 at 22:26
  • Good point about the default # (rawlen) being able to be overridden by __len. One note about rawlen, though: It applies only to tables with a sequence. Array is an implementation detail. The standard implementation can have an array part even when the table doesn't have a sequence. – Tom Blodget Oct 28 '14 at 23:45
0

The only way is to iterate through entries and count them. Iterate with ipair through the item and increment counter then return result.

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

The # operator only work for hash table type.

See: How to get number of entries in a Lua table?

Community
  • 1
  • 1
GrandMarquis
  • 1,913
  • 1
  • 18
  • 30
  • I don't want to get the lenght of the table, that's not the question here. But beside this, what is a ash table? Even the russian friends from google don't know. – jawo Oct 28 '14 at 11:50
  • Sorry i misunderstood your question. I was speaking of hash array.. Typo. But you can use this method to get the last index. – GrandMarquis Oct 28 '14 at 11:53
  • `#` explicitly does *not* work for tables with non-numeric indices. – Etan Reisner Oct 28 '14 at 11:59
  • It does not work für the fields with non-numeric indices, as argued it counts the numeric indeces from lowest to n or gap. – jawo Oct 28 '14 at 12:02