我怎么知道一个表是否是一个数组?

Ale*_*ack 11 lua

我正在开发一个简单的优化JSON函数.Lua使用表来表示数组,但在JSON中我需要在它们之间进行识别.使用以下代码:

t={
    a="hi",
    b=100
}

function table2json(t,formatted)
if type(t)~="table" then return nil,"Parameter is not a table. It is: "..type(t)    end

local ret=""--return value
local lvl=0 --indentation level
local INDENT="  " --OPTION: the characters put in front of every line for indentation
function addToRet(str) if formatted then ret=ret..string.rep(INDENT,lvl)..str.."\n" else ret=ret..str end end

addToRet("{")
lvl=1
for k,v in pairs(t) do
    local typeof=type(v)
    if typeof=="string" then
        addToRet(k..":\""..v.."\"")
    elseif typeof=="number" then
        addToRet(k..":"..v)
    end
end
lvl=0
addToRet("}")

return ret
end

print(table2json(t,true))
Run Code Online (Sandbox Code Playgroud)

正如你在JSON参考中看到的那样,在Lua中object称为a table,它与a 不同array.

问题是如何检测表是否被用作数组?

  • 当然,一种解决方案是遍历所有对,看看它们是否只有数字连续键但是速度不够快.
  • 另一个解决方案是在表中放置一个标志,表示它是一个数组而不是一个对象.

任何更简单/更智能的解决方案?

sbk*_*sbk 9

如果你想要快速,简单,非侵入式的解决方案,大多数时候都可以工作,那么我只想检查索引1 - 如果它存在,那么表就是一个数组.当然,没有保证,但根据我的经验,表很少有数字键和其他键.你是否可以将某些对象误认为数组,以及你是否希望这种情况发生,这通常取决于你的使用场景 - 我想这对于一般的JSON库来说并不好.

编辑:对于科学,我去看看Lua CJSON是如何做的.它遍历所有对并检查所有键是否为整数,同时保持最大键(相关功能lua_array_length).然后它决定是否将表序列化为数组或对象,具体取决于表的稀疏程度(用户控制的比率),即索引为1,2,5,10的表可能会被序列化为数组而指数1,2,1000000将作为对象.我想这实际上是非常好的解决方案.


小智 6

这是基于 Lua 特定 #len 函数机制的更简单的检查。

function is_array(table)
  if type(table) ~= 'table' then
    return false
  end

  -- objects always return empty size
  if #table > 0 then
    return true
  end

  -- only object can have empty length with elements inside
  for k, v in pairs(table) do
    return false
  end

  -- if no elements it can be array and not at same time
  return true
end

local a = {} -- true
local b = { 1, 2, 3 } -- true
local c = { a = 1, b = 1, c = 1 } -- false
Run Code Online (Sandbox Code Playgroud)

  • 有用。你可以稍微缩短一下:“function is_array(tbl) return type(tbl) == 'table' and (#tbl > 0 or next(tbl) == nil) end”。 (2认同)

kik*_*ito 5

区分数组/非数组的最简单算法是这个:

local function is_array(t)
  local i = 0
  for _ in pairs(t) do
      i = i + 1
      if t[i] == nil then return false end
  end
  return true
end
Run Code Online (Sandbox Code Playgroud)

此处说明:https : //web.archive.org/web/20140227143701/http : //ericjmritz.name/2014/02/26/lua-is_array/

也就是说,您仍然会遇到空表的问题——它们是“数组”还是“散列”?

对于序列化 json 的特殊情况,我所做的是用元表中的字段标记数组。

-- use this when deserializing
local function mark_as_array(t)
  setmetatable(t, {__isarray = true})
end

-- use this when serializing
local function is_array(t)
  local mt = getmetatable(t)
  return mt.__isarray
end
Run Code Online (Sandbox Code Playgroud)