可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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.
回答2:
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
回答3:
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
回答4:
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
回答5:
I wrote this code for another similar question lately:
---Checks if a table is used as an array. That is: the keys start with one and are sequential numbers
-- @param t table
-- @return nil,error string if t is not a table
-- @return true/false if t is an array/isn't an array
-- NOTE: it returns true for an empty table
function isArray(t)
if type(t)~="table" then return nil,"Argument is not a table! It is: "..type(t) end
--check if all the table keys are numerical and count their number
local count=0
for k,v in pairs(t) do
if type(k)~="number" then return false else count=count+1 end
end
--all keys are numerical. now let's see if they are sequential and start with 1
for i=1,count do
--Hint: the VALUE might be "nil", in that case "not t[i]" isn't enough, that's why we check the type
if not t[i] and type(t[i])~="nil" then return false end
end
return true
end
回答6:
Here's my take on this, using #array
to detect a gap or stop when too many keys have been read:
function isArray(array)
local count=0
for k,_ in pairs(array) do
count=count+1
if (type(k) ~= "number" or k < 1 or k > #array or count > #array or math.floor(k) ~= k) then
return false
end
end
if count ~= #array then
return false
end
return true
end
回答7:
Iterate from 0 to the number of elements, and check if all elements with the counter's index exist. If it's not an array, some indexes will miss in the sequence.