如何计算两个列表的所有交错?

时间:2013-03-09 01:45:45

标签: python algorithm

我想创建一个接收两个列表的函数,列表不保证长度相等,并返回两个列表之间的所有交错。

输入:两个不必相等的列表。

输出:保留原始列表顺序的两个列表之间的所有可能交错。

示例: AllInter([1,2],[3,4]) - > [[1,2,3,4],[1,3,2,4],[1,3,4,2],[3,1,2,4],[3,1,4,2] ,[3,4,1,2]]

我不想要解决方案。我想要一个提示。

4 个答案:

答案 0 :(得分:5)

Itertools不足以处理这个问题,需要对钉子和孔问题有一些了解

考虑您的示例列表

A = [1,2] B = [3,4]

有四个洞(len(A) + len(B)),您可以放置​​元素(钉子)

|   ||   ||   ||   |
|___||___||___||___|

在Python中,您可以将空插槽表示为None

的列表
slots = [None]*(len(A) + len(B))

您可以将第二个列表中的元素(桩)放入栓钉中的方式很简单,就是可以从孔中选择槽的方式的数量

len(A) + len(B) C <子> len(B)

= 4 C 2

= itertools.combinations(range(0, len(len(A) + len(B)))

可以描述为

|   ||   ||   ||   |  Slots
|___||___||___||___|  Selected

  3    4              (0,1)
  3         4         (0,2)
  3              4    (0,3) 
       3    4         (1,2) 
       3         4    (1,3)
            3    4    (2,3)   

现在,对于每个槽位置,用第二个列表中的元素(桩)填充它

for splice in combinations(range(0,len(slots)),len(B)):
    it_B = iter(B)
    for s in splice:
        slots[s] = next(it_B)

完成后,您只需用第一个列表中的元素(挂钩)填充剩余的空插槽

    it_A = iter(A)
    slots = [e if e else next(it_A) for e in slots]

在开始下一次迭代与另一个插槽位置之前,冲洗你的洞

    slots = [None]*(len(slots))

上述方法的Python实现

def slot_combinations(A,B):
    slots = [None]*(len(A) + len(B))
    for splice in combinations(range(0,len(slots)),len(B)):
        it_B = iter(B)
        for s in splice:
            slots[s] = next(it_B)
        it_A = iter(A)
        slots = [e if e else next(it_A) for e in slots]
        yield slots
        slots = [None]*(len(slots))

以上实施中的O / P

list(slot_combinations(A,B))
[[3, 4, 1, 2], [3, 1, 4, 2], [3, 1, 2, 4], [1, 3, 4, 2], [1, 3, 2, 4], [1, 2, 3, 4]]

答案 1 :(得分:2)

提示:假设每个列表具有相同的元素(但列表之间不同),即一个列表完全是红色(比如r),另一个列表是蓝色(比如b)。

输出的每个元素都包含r + b或它们,其中r为红色。

似乎其他人已经为你破坏了它,即使你没有要求解决方案(但他们有一个非常好的解释)

所以这里是我写的代码很快。

import itertools

def interleave(lst1, lst2):
    r,b = len(lst1), len(lst2)
    for s in itertools.combinations(xrange(0,r+b), r):
        lst = [0]*(r+b)
        tuple_idx,idx1,idx2 = 0,0,0
        for i in xrange(0, r+b):
            if tuple_idx < r and i == s[tuple_idx]:
                lst[i] = lst1[idx1]
                idx1 += 1
                tuple_idx += 1
            else: 
                lst[i] = lst2[idx2]
                idx2 += 1
        yield lst


def main():
    for s in interleave([1,2,3], ['a','b']):
        print s

if __name__ == "__main__":
    main()

基本思路是将输出映射到(r + b)选择r组合。

答案 2 :(得分:1)

正如@airza所建议的,itertools模块是你的朋友。

如果你想避免使用封装的魔法善良,我的提示是使用递归。

开始在您的脑海中播放生成列表的过程,当您发现自己再次做同样的事情时,尝试找到模式。例如:

  1. 从第一个列表中取出第一个元素
  2. 从第二个或第一个列表中取出第一个
  3. 如果不这样做,可以选择第3个或第2个,或者从另一个列表中选择另一个
  4. ...
  5. 好的,这开始看起来有一些我们没有使用的更大逻辑。我只是递增数字。当然,我可以找到一个可以在更改“第一个元素而不是命名更高元素的情况下工作的基础案例吗?

    玩它。 :)

答案 3 :(得分:0)

你可以尝试更接近金属的东西,更优雅(在我看来)迭代不同的可能切片。基本上逐步执行并遍历标准切片操作的所有三个参数,删除添加到最终列表的任何内容。如果您有兴趣,可以发布代码片段。