从Lua表中随机选择一个键。

我想使用Lua中可能的项目列表随机填充网格,其定义如下:

  -- 项目
  items = {}
  items.glass = {}
  items.glass.color = colors.blue
  items.brick = {}
  items.brick.color = colors.red
  items.grass = {}
  items.grass.color = colors.green

因此,表的键为“glass”,“brick”和“grass”。

如果它们不能通过数值索引进行寻址,如何随机选择其中之一的键?

点赞
用户274354
用户274354

嗯,我找到了一个解决方法,但我也愿意听听更好的建议。

第一个解决方案是建立一个辅助表作为第一个表的索引:

item_index = {"grass", "brick", "glass"}

然后我可以随机存储这个表的键(board是一个存储item_index中随机条目的值的矩阵):

local index = math.random(1,3)
board[i][j] = item_index[index]

接下来,我可以按以下方式获取原始列表的详细信息:

items[board[y][x]].color

我决定采用的第二个解决方案是将定义的元素作为数组元素添加到原始表中:

  -- Items
  items = {}
  items.glass = {}
  items.glass.color = colors.blue
  table.insert(items, items.glass)   --- 将项作为数组项添加
  items.brick = {}
  items.brick.color = colors.red
  table.insert(items, items.brick)   --- 将项作为数组项添加
  items.grass = {}
  items.grass.color = colors.green
  table.insert(items, items.grass)   --- 将项作为数组项添加

然后,我可以直接使用索引直接访问这些元素:

  local index = math.random(1,3)
  board[i][j] = items[index]

它们可以直接检索,无需进行额外的查找:

  board[y][x].color
2014-03-11 09:27:58
用户869951
用户869951

虽然你的第二种方法语法简洁,但我认为第一种更容易维护。虽然我无法在这里进行测试,但我认为你可以兼得两者的优点,这样行得通:

local items = {
    glass = {
        color = colors.blue,
    },
    brick = {
        color = colors.red,
    },
    grass = {
         color = colors.green,
    },
}
local item_index = {"grass", "brick", "glass"}
local index = math.random(1,3)
board[i][j] = items[item_index[index]]
print('color:', board[i][j].color)
2014-03-11 14:03:12
用户988143
用户988143

如果你的表不太大,你可以在任意位置断开。这种方法假定你知道表中的条目数量(它不等于#table的值,如果表具有非数字键)。

因此,首先找到表的长度,然后在random(1, length(table))处断开,就像这样:

local items = {} ....
items.grass.color = colors.green

local numitems = 0 -- 找出表的大小
for k,v in pairs(items) do
    numitems = numitems + 1
end

local randval = math.random(1, numitems) -- 获取随机点

local randentry
local count = 0
for k,v in pairs(items) do
    count = count + 1
    if(count == randentry) then
        randentry = {key = k, val = v}
        break
    end
end

好处:您不需要跟踪键。它可以是任何表,您不需要维护它。 坏处和问题:它是O(n)——两个线性通道,因此,如果您有一个大表,这绝不是理想的选择。

2014-03-11 15:18:49
用户2662300
用户2662300

上面的回答假设你知道所有键的内容,这是我今天早些时候无法做到的。我的解决方案:

function table.randFrom( t )
    local choice = "F"
    local n = 0
    for i, o in pairs(t) do
        n = n + 1
        if math.random() < (1/n) then
            choice = o
        end
    end
    return choice
end

解释:我们不能使用 table.getn(t)来获取表的大小,因此我们在使用过程中进行了跟踪。第一项将有1/1 = 1的选择机会。 第二项将有1/2 = 0.5的选择机会,以此类推……

如果扩展到N个项目,第N个项目将有1/N的被选择机会。第一项将有1-(1/2)-(1/3)-(1/4)-……-(1/N)的不被替换机会(记住,它总是最初被选择的)。该系列收敛于1-(N-1)/N = 1/N,等于选择最后一项的机会。

因此,数组中的每个项目具有相等的随机选择机会;它是均匀随机的。这也以O(n)的时间运行,这不是很好,但如果您不知道索引名称,这是您所能做的最好的事情。

2015-01-18 01:43:27