如何在Lua中制作一个函数,从不重复选取相同的数字

我正在尝试编写一个生成随机数字但不重复的函数。

这是我目前的代码,但它不起作用。它可以编译,但在数组中多次插入相同的数字。

quiz = 10
array = {}
array[1] = 0 -- 只是为了有一个东西在里面,否则我的循环就不起作用了...
ok = false

repeat
    rdm = math.ceil(math.random() * quiz)

    for i = 0, #array do
        if(rdm == array[i]) then
            break -- 打破 for 循环以选择一个新数字
        elseif(rdm ~= array[i]) then
            ok = true -- 结束 repeat 循环
            table.insert(array, rdm) -- 记录到目前为止所获得的内容
        end
    end
until ok == true

for b = 0, #array do -- #array 应该是十
    print(array[b])
end

它会生成多次相同的数字,并说它与表中的数字不同...

我想我的问题来自于逻辑...但我不知道从哪里来,因为对我来说它都是有意义的。

点赞
用户869951
用户869951

如果你知道你需要的随机数最多是 N 个,你可以预先生成随机数并将它们按值插入到表中。然后你的函数从表中随机选择一个数并删除它。代码如下:

local rands = {}
local numRands = 100

-- populate table of random numbers
while #rands < numRands do
    local r = math.random(1,1000)
    rands[r]=r -- 如果有重复,表格中保持不变
end

local function getNeverSameRandom()
    local index = math.random(1,numRands)
    return table.remove(rands, index)
end

如果您不知道需要填充的数量,则通过表跟踪:

local randsUsed = {}
local maxRand = 1000000 -- 您想要的最大随机数
local function getNeverSameRandom()
    local rnd
    repeat
         rnd = math.random(1,maxRand)
    until randsUsed[rnd] == nil
    randsUsed[rnd] = rnd
    return rnd
end

当然问题在于,如果您多次调用 getNeverSameRandom,例如半个最大随机数,那么您的randsUsed表将变得相当满,并且 repeat-until 将会变得越来越长。最终,表将会满,函数将会陷入无限循环。您可以通过计数器轻松检查,但是您不能使用 #randsUsed,因为 randsUsed 是一个带有"空洞"的表,因此不能使用#运算符。例如:

local randsUsedCount  = 0
local function getNeverSameRandom()
    if randsUsedCount == maxRand then
        error("No more random #'s left in range 1-"..maxRand)
    end
    local rnd
    repeat
         rnd = math.random(1,maxRand)
    until randsUsed[rnd] == nil
    randsUsed[rnd] = rnd
    randsUsedCount = randsUsedCount  + 1
    return rnd
end
2014-02-22 05:50:33
用户1442917
用户1442917

最简单的方法可能是预先填充一个元素数组,使用您需要的序列(例如,1..1000),然后使用类似Fisher-Yates 算法的方法就地洗牌:

local rands, n = {}, 1000
-- 预先填充
for i = 1, n do rands[i] = i end
-- 洗牌
for i = n, 2, -1 do
  local j = math.random(i)
  rands[j], rands[i] = rands[i], rands[j]
end
-- 使用
print(table.remove(rands))

同样的页面还有“inside-out”版本算法,可以完成初始化和洗牌两个步骤。

2014-02-22 06:55:23