【问题标题】:"wolf, carrot, goat" riddle on steroids (generating a table in lua)关于类固醇的“狼,胡萝卜,山羊”之谜(在 lua 中生成一个表)
【发布时间】:2014-02-03 08:50:53
【问题描述】:

我有一个包含大量元素的数组,并希望以尽可能多的方式对它们进行分组,使每个组成为一个新数组中的一个元素。但是,某些元素是不兼容的,例如:

objects = {a, b, c, d}
incompatible = {{a,b}, {a,d}, {c,d}}

我想生成一个数组,其中包含所有兼容的对象排列,没有重复。这个数组的一个元素可以包含任意数量的对象,甚至是单例,只要它的内容都是兼容的。

在上面的例子中,它看起来像这样:

compatible_groups = {{},{a},{b},{c},{d},{a,c},{b,c},{b,d}}

我考虑的一个可能的解决方案是一个函数,它接受任意数量的参数,将它们全部相互比较,例如:

function generate_groups(...)
    local arg={...}
    for i=1, #arg-(n+0) do -- only looping partially through array to prevent repeats
        for j=i+1, #arg-(n+1) do
            for k=j+1, #arg-(n+2) do
               ...

但要让它工作,我需要有与函数有参数一样多的嵌套 for 循环。不知道该怎么做。

一旦解决了,检查两个参数是否构成不兼容数组的元素之一将是相当简单的。

for i=1, #incompatible
if arg[a][1] == incompatible[a][1] and arg[a][2] == incompatible[a][2]...

所以我认为无论如何。我在这里缺少一种更简单的方法吗?

【问题讨论】:

    标签: arrays function lua lua-table


    【解决方案1】:

    您可以先生成列表的所有可能排列,然后减去您不想要的项目。

    您可以使用递归来生成排列,而无需大量循环。见Algorithm to generate all possible permutations of a list?。您可以调整算法以检查您的过滤表并简单地忽略违规结果,或者在之后将它们从结果中删除。

    【讨论】:

    • 请注意,“排列”不等于“组合”。我相信算法是完全不同的。
    • 对,这个想法是确定有多少种合法的方法可以将项目列表组合成组。您对尾递归而不是嵌套循环的想法听起来很吸引人,但是排列将需要大量浪费的计算,需要过滤掉。
    • 好吧,同样的想法也适用;只需生成组合而不是排列,然后过滤掉您不想要的项目。不过,Schollii 的回答更完整。
    【解决方案2】:

    注意,如果你有一个长度为 n 的列表的所有组合的集合 S(n),它等于 S(n-1) + {list[1] 与 S(n-1) 中的每个组合其中 S(n-1) 是列表中 n-1 个最右边项的所有组合的集合。这意味着您可以使用递归函数。由于 Lua 没有拼接操作(与 python 或 lisp 不同),我们使用索引“rightLen”,它是要使用的 # 个项目,从右端开始:

    function getAllCombinations(list, rightLen)
        local N = #list
        rightLen = rightLen or N
        if rightLen <= 1 then 
            return {{}, {list[N]}}
        end
        local combosNm1 = getAllCombinations(list, rightLen-1)
        local combos = table.copy(combosNm1)
        local addItem = list[N-rightLen+1]
        for i,combo in ipairs(combosNm1) do
            table.insert(combo, addItem)
            table.insert(combos, combo)
        end
        return combos 
    end
    

    table.copy 被定义为

    function table.copy(tt)
        local newT = {}
        for i,t in ipairs(tt) do
            if type(t) == 'table' then
                table.insert(newT, table.copy(t))
            else
                table.insert(newT, t)
            end
        end
        return newT
    end
    

    我不知道这是否是最好的性能。 14 个项目在我的笔记本电脑虚拟机上看起来是瞬时的,17 个项目需要 1 秒,19 个项目需要 5 秒。当然是指数增长。副本很讨厌,也许以下会给出更快的结果:

    local combos = {} -- old: table.copy(combosNm1)
    local addItem = list[N-rightLen+1]
    for i,combo in ipairs(combosNm1) do
        table.insert(combos, combo)
        extCombo = table.copy(combo)
        table.insert(extCombo, addItem)
        table.insert(combos, extCombo)
    end
    

    而 table.copy 可以简单地是

    function table.copy(tt)
        local newT = {}
        for i,t in ipairs(tt) do
             newT[i] = t
        end
        return newT
    end
    

    这似乎快了大约 40%。

    【讨论】:

    • 最好将其转换为利用 Lua 的尾调用的算法,以便不受函数调用堆栈限制的限制。也可能获得性能。
    • 这很可能是我的问题的答案,但是在玩了几个小时的代码之后,我仍然觉得它在我的头上。我会坚持一段时间,如果我能让它工作,那就把它作为答案。谢谢!
    • @etothepowerofx 它不会产生您正在寻找的组合吗?你不明白什么?
    • 这段代码的工作原理和宣传的一样,但是我在没有进一步研究的情况下理解它有些困难。谢谢!
    • @etothepowerofx 很高兴听到。希望您知道在哪里为您的排除添加过滤器,当涉及排除时,第二种方法会更有效。
    猜你喜欢
    • 1970-01-01
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    相关资源
    最近更新 更多