jawo
jawo

Reputation: 896

Non numeral indeces and the # never counts?

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?

Upvotes: 1

Views: 164

Answers (3)

Etan Reisner
Etan Reisner

Reputation: 81052

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.

Upvotes: 3

kikito
kikito

Reputation: 52708

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

Upvotes: 2

GrandMarquis
GrandMarquis

Reputation: 1913

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?

Upvotes: 0

Related Questions