Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I check if a lua table contains only sequential numeric indices?

How can I write a function that determines whether it's table argument is a true array?

isArray({1, 2, 4, 8, 16}) -> true
isArray({1, "two", 3, 4, 5}) -> true
isArray({1, [3]="two", [2]=3, 4, 5}) -> true
isArray({1, dictionaryKey = "not an array", 3, 4, 5}) -> false

I can't see any way of finding out if the numeric keys are the only keys.

like image 853
Eric Avatar asked May 20 '11 19:05

Eric


People also ask

Are Lua tables ordered?

Note that, for Lua, arrays also have no order.

How do I check if an array is Lua?

The question is how I can detect if a table is being used as an array? One solution of course is to go through all pairs and see if they only have numerical consecutive keys but that's not fast enough. Another solution is to put a flag in the table that says it is an array not an object.

Are Lua tables arrays?

Lua uses associative arrays and which can be indexed with not only numbers but also with strings except nil. Tables have no fixed size and can grow based on our need.

How are Lua tables stored in memory?

Instead, Lua programmers use regular tables with integer indices to implement arrays. Lua 5.0 uses a new algorithm that detects whether tables are being used as arrays and automatically stores the values associated to numeric indices in an actual array, instead of adding them to the hash table.


4 Answers

EDIT: Here's a new way to test for arrays that I discovered just recently. For each element returned by pairs, it simply checks that the nth item on it is not nil. As far as I know, this is the fastest and most elegant way to test for array-ness.

local function isArray(t)
  local i = 0
  for _ in pairs(t) do
    i = i + 1
    if t[i] == nil then return false end
  end
  return true
end
like image 75
kikito Avatar answered Oct 09 '22 07:10

kikito


ipairs iterates over indices 1..n, where n+1 is the first integer index with a nil value
pairs iterates over all keys.
if there are more keys than there are sequential indices, then it cannot be an array.

So all you have to do is see if the number of elements in pairs(table) is equal to the number of elements in ipairs(table)
the code can be written as follows:

function isArray(tbl)
    local numKeys = 0
    for _, _ in pairs(tbl) do
        numKeys = numKeys+1
    end
    local numIndices = 0
    for _, _ in ipairs(tbl) do
        numIndices = numIndices+1
    end
    return numKeys == numIndices
end

I'm pretty new to Lua, so there might be some builtin function to reduce the numKeys and numIndices calculations to simple function calls.

like image 36
Ponkadoodle Avatar answered Oct 09 '22 09:10

Ponkadoodle


By "true array", I suppose you mean a table whose keys are only numbers. To do this, check the type of every key of your table. Try this :

function isArray(array)
    for k, _ in pairs(array) do
        if type(k) ~= "number" then
            return false
        end
    end
    return true --Found nothing but numbers !
end
like image 31
SolarBear Avatar answered Oct 09 '22 07:10

SolarBear


Note: as @eric points out, pairs is not defined to iterate in a specific order. Hence this is no valid answer.

The following should be sufficient; it checks that the keys are sequential from 1 until the end:

local function isArray(array)
  local n = 1
  for k, _ in pairs(array) do
    if k ~= n then return false end
    n = n + 1
  end

  return true
end
like image 44
radiospiel Avatar answered Oct 09 '22 07:10

radiospiel