Merging 2 Lists In Multiple Ways - Python

时间:2016-05-11 11:30:04

标签: python list combinations permutation

I've been experimenting with a number of techniques but I'm sure there's smooth-ish way to get this done.

Suppose I have two lists with the same amount of items in them (4 each):

a = ['a', 'b', 'c', 'd']    
b = [1, 2, 3, 4]

I'd like to merge these lists in all possible ways while retaining order. Example outputs:

a, b, c, d, 1, 2, 3, 4    
1, 2, 3, 4, a, b, c, d    
a, b, 1, 2, c, 3, 4, d

The point is each of the lists must retain its order so an item can not precede another item in the output considering its position in the list. so for example the output can not be:

a, b, **d**, c, 1...   > d precedes c whereas c is before d in the original list
1, **4**, a, b, 3....  > 4 precedes 3 whereas 3 is before 4 in the original list

I guess the idea is to merge the second list into the first list in all possible ways. A fully worked example is this:

a = [a, b]    
b = [1, 2]

desired output:

ab12                                                                      
a1b2                                                                             
a12b                                                                         
1ab2                                                                             
1a2b                                                                          
12ab

How do I go about doing this? Does itertools have a capability to do this in some way? Or is there another way to get this done? Please help!

5 个答案:

答案 0 :(得分:6)

在2x4的情况下,您希望在不中断每个四边形内的排序的情况下获取所有8个元素。这些例子:

a, b, c, d, 1, 2, 3, 4    
1, 2, 3, 4, a, b, c, d    
a, b, 1, 2, c, 3, 4, d

可以转换成"指令序列"这些是从0或1中取得的列表:

0 0 0 0 1 1 1 1
1 1 1 1 0 0 0 0
0 0 1 1 0 1 1 0

一旦你意识到这一点,你可能会注意到我们需要生成的序列是四个零和四个的所有排列。实现这一飞跃后,我们可以使用itertools

itertools.permutations([0,0,0,0,1,1,1,1])

对于2x4情况,这给出了40320个结果,但只有70个唯一的结果(因为itertools.permutations认为1,1,1与1,1,1不同,如果数字被重新排序)。您可以在此处获得答案中的唯一排列:https://stackoverflow.com/a/6285330/4323或只使用set()

总而言之,这是一个完整的解决方案:

import itertools

def combos(*seqs):
    counts = map(len, seqs)
    base = []
    for ii, count in enumerate(counts):
        base.extend([ii]*count)
    for take in set(itertools.permutations(base)):
        result = []
        where = [0] * len(seqs)
        for elem in take:
            result.append(seqs[elem][where[elem]])
            where[elem] += 1
        yield result

你可以这样测试(给出70个结果):

a = ['a', 'b', 'c', 'd']
b = [1, 2, 3, 4]

for res in combos(a, b):
    print res

答案 1 :(得分:1)

使用python的递归方法:

for(int i=0;i<cruiseDetails.Count();i++)
{

    cruiseDetails[i].additionalKey = val;
}

答案 2 :(得分:1)

一种选择是使用一个计数器,其中设置位对应于a上的项目,而未设置为b上的项目。对于计数器中的每个值,检查是否设置了len(a)位并生成排列:

def ordered_permutations(l1, l2):
    length = len(l1) + len(l2)
    fmt = '{{0:0{0}b}}'.format(length)

    for i in xrange(2 ** length):
        seq = fmt.format(i)

        if seq.count('1') == len(l1):
            iters = [iter(l1), iter(l2)]
            yield [iters[int(c)].next() for c in seq]

用法:

for p in ordered_permutations(['a','b'], [1,2]):
    print p

输出:

['a', 'b', 1, 2]
['a', 1, 'b', 2]
['a', 1, 2, 'b']
[1, 'a', 'b', 2]
[1, 'a', 2, 'b']
[1, 2, 'a', 'b']

通过使用HAKMEM 175生成下一个序列而不是使用计数器并检查是否设置了正确的位数,可以改进实现。

答案 3 :(得分:0)

替代选项是使用递归。

伪代码:

result[] SortedMergePermutations(listA,listB)
{
  result.append([FirstElementOfListA, 
    SortedMergePermutations(listAWithoutFirstElement,listB))]
  result.append([FirstElementOfListB,
    SortedMergePermutations(listA,listBWithoutFirstElement))]
  ])
  return result
}

答案 4 :(得分:0)

我找到了一个仅适用于两个序列的解决方案,但使用itertools.combinations()来查找可能的位置序列(按顺序排列)第一个序列的元素

from __future__ import print_function

def print_merged(a, b):
    from itertools import combinations, cycle

    l = len(a) + len(b)
    ab = [cycle(a), cycle(b)]
    rng = range(l)
    print([a, b])

    for index in combinations(rng, len(a)):
        li = []
        for i in rng:
            n = 0 if i in index else 1
            li.append(next(ab[n]))
        print(li)

# testing

print_merged([1,2,3], [4,5,6])
print('-'*72)
print_merged([1,2], [4,5,6])
print('-'*72)
print_merged([1,2,3], [5,6])

我模糊地理解,可以处理大量的列表,将第3个列表与第一个和第二个列表中生成的每个列表合并,等等,这个想法指向递归实现的方向,但是我很高兴将这样的成就留给别人......

编辑1

我删除了计数器机器,因为itertools.cycle()对象正是所需的。

测试输出

[[1, 2, 3], [4, 5, 6]]
[1, 2, 3, 4, 5, 6]
[1, 2, 4, 3, 5, 6]
[1, 2, 4, 5, 3, 6]
[1, 2, 4, 5, 6, 3]
[1, 4, 2, 3, 5, 6]
[1, 4, 2, 5, 3, 6]
[1, 4, 2, 5, 6, 3]
[1, 4, 5, 2, 3, 6]
[1, 4, 5, 2, 6, 3]
[1, 4, 5, 6, 2, 3]
[4, 1, 2, 3, 5, 6]
[4, 1, 2, 5, 3, 6]
[4, 1, 2, 5, 6, 3]
[4, 1, 5, 2, 3, 6]
[4, 1, 5, 2, 6, 3]
[4, 1, 5, 6, 2, 3]
[4, 5, 1, 2, 3, 6]
[4, 5, 1, 2, 6, 3]
[4, 5, 1, 6, 2, 3]
[4, 5, 6, 1, 2, 3]
------------------------------------------------------------------------
[[1, 2], [4, 5, 6]]
[1, 2, 4, 5, 6]
[1, 4, 2, 5, 6]
[1, 4, 5, 2, 6]
[1, 4, 5, 6, 2]
[4, 1, 2, 5, 6]
[4, 1, 5, 2, 6]
[4, 1, 5, 6, 2]
[4, 5, 1, 2, 6]
[4, 5, 1, 6, 2]
[4, 5, 6, 1, 2]
------------------------------------------------------------------------
[[1, 2, 3], [5, 6]]
[1, 2, 3, 5, 6]
[1, 2, 5, 3, 6]
[1, 2, 5, 6, 3]
[1, 5, 2, 3, 6]
[1, 5, 2, 6, 3]
[1, 5, 6, 2, 3]
[5, 1, 2, 3, 6]
[5, 1, 2, 6, 3]
[5, 1, 6, 2, 3]
[5, 6, 1, 2, 3]