Lua 成对排列,顺序与编写时相同

Posted

技术标签:

【中文标题】Lua 成对排列,顺序与编写时相同【英文标题】:Lua in pairs with same order as it's written 【发布时间】:2015-09-07 07:39:41 【问题描述】:

有没有什么方法可以按照与下面的表格相同的顺序循环遍历表格?

local tbl = 
    ["hello"] = 1,
    [2] = 2,
    [50] = 3,
    ["bye"] = 4,
    [200] = 5

我的意思是,当我使用“成对”时,每次执行代码时都会得到不同的顺序...

我正在寻找这样的东西:

function get_keys(tbl)
    local rtable = 
    for k,v in pairs(tbl) do
        table.insert(rtable, k)
    end
    return rtable
end

local keys_of_tbl = get_keys(tbl)
for i = 1, table.getn(keys_of_tbl) do
    --Do something with: tbl[keys_of_tbl[i]]
end

但是因为“get_keys”这个函数又是基于“成对”的,​​所以就不行了……

【问题讨论】:

这些值是您想要循环的顺序吗?或者这只是巧合? 我想以与写入相同的顺序循环遍历表“tbl”,所以第一个 gotrough 应该是键“hello”,第二个 2,第三个 50,... 当有人没有意识到订单很重要时出于某种原因重新安排事情时,依赖源内订单会在以后提出问题。如果您需要明确的订单,请明确订单。 我为我的问题添加了另一个可行的解决方案:) 【参考方案1】:

在 Lua 中,pair 遍历键的顺序是未指定的。但是,您可以保存在数组样式表中添加项目的顺序并使用ipairs(它具有在数组中迭代键的定义顺序)。为了帮助解决这个问题,您可以使用元表创建自己的有序表,以便在添加新键时保持键顺序。


EDIT(之前的代码在更新时插入了多个密钥副本)

为此,您可以使用__newindex,只要索引尚未添加到表中,我们就会调用它。 ordered_add 方法更新、删除或存储隐藏表 _keys_values 中的键。请注意,__newindex 在我们更新键时总是会被调用,因为我们没有将值存储在表中,而是将其存储在“隐藏”表中 _keys_values

但请注意,我们不能在此表中使用任何键,键名称 "_keys" 将覆盖我们的隐藏表,因此更安全的替代方法是使用 ordered_table.insert(t, key, value) ordered_table.index(t, key)ordered_table.remove(t, key) 方法。

ordered_table = 

function ordered_table.insert(t, k, v)
  if not rawget(t._values, k) then -- new key 
    t._keys[#t._keys + 1] = k
  end
  if v == nil then -- delete key too.
    ordered_table.remove(t, k)
  else -- update/store value
    t._values[k] = v 
  end
end

local function find(t, value)
  for i,v in ipairs(t) do
    if v == value then
      return i
    end
  end
end  

function ordered_table.remove(t, k)
  local v = t._values[k]
  if v ~= nil then
    table.remove(t._keys, find(t._keys, k))
    t._values[k] = nil
  end
  return v
end

function ordered_table.index(t, k)
    return rawget(t._values, k)
end

function ordered_table.pairs(t)
  local i = 0
  return function()
    i = i + 1
    local key = t._keys[i]
    if key ~= nil then
      return key, t._values[key]
    end
  end
end

function ordered_table.new(init)
  init = init or 
  local t = _keys=, _values=
  local n = #init
  if n % 2 ~= 0 then
    error"in ordered_table initialization: key is missing value"
  end
  for i=1,n/2 do
    local k = init[i * 2 - 1]
    local v = init[i * 2]
    if t._values[k] ~= nil then
      error("duplicate key:"..k)
    end
    t._keys[#t._keys + 1]  = k
    t._values[k] = v
  end
  return setmetatable(t,
    __newindex=ordered_table.insert,
    __len=function(t) return #t._keys end,
    __pairs=ordered_table.pairs,
    __index=t._values
    )
end

--- Example Usage:
local t = ordered_table.new
  "hello", 1,  -- key, value pairs
  2, 2,
  50, 3,
  "bye", 4,
  200, 5


print(#t)
print("hello is", t.hello)
print()
for k, v in pairs(t) do  --- Lua 5.2 __pairs metamethod
  print(k, v)
end
t.bye = nil -- delete that
t[2] = 7 -- use integer keys
print(#t) 

【讨论】:

作为一项规则,没有人可以对从他们的代码中做出的所有可能的错误推断负责;做某事的错误方法太多了。我已经抽象出搜索,现在删除显然不在循环中,我希望这能让我们俩都满意:) 这对我有用。 =) 谢谢。这是我在 github/etc 上看到的代码吗?我不会对此发表评论(或根本不会考虑太多)。但特别是在 SO 和网站及其目标受众提供的帮助的长尾意图的背景下,我认为解决方案应该尽可能减少“阻碍”。【参考方案2】:

没有。表格没有“如源代码中所写”的顺序。 (考虑并非所有键都必须存在于源中。)对于非连续整数键,lua 没有“按顺序”的概念。

如果您想要特定订单,您可以通过某种方式自己手动保留该订单。

如果您的表中没有任何整数键,那么您可以使用它们作为您的订单(并使用 ipairs 循环这些键并将值作为键来获取实际值)。

如果您的原始值是您想要排序的顺序,那么您可以循环和反向映射以获得一个表格,您可以在完成后使用ipairs 进行迭代。

【讨论】:

谢谢,我会走那条路……虽然没有想象中那么好,但如果不可能,这将是 x.x 的单一方式

以上是关于Lua 成对排列,顺序与编写时相同的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 使用 Realm 和 Swift 具有多个按字母顺序排列的部分,多个标签与相同的数据连接

两个Excel有一列内容相同,这一列排列顺序不一样,怎么把这两个表内容合并成一张表?

Lua 数组

Lua之数组

3位反序数

当排列数中出现相同的数时,逆序数怎么计算,比如145243