是否有算法可以找到2个列表的唯一组合? 5个名单?

时间:2009-11-19 16:10:58

标签: php python algorithm

我有 N 列表我想找到独特的组合。我已经把它写在我的白板上了,它似乎都有一个模式,我还没有找到它。我觉得我可以表达一种蛮力的方法,这肯定是我追求的东西。还有其他选择吗?不同的数据结构(二叉树吗?)会使这样的工作更合适吗?

鉴于

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

结果将是:

c = [1a, 1b, 2a, 2b] # (4 unique combinations)

鉴于

v = [1, a]
w = [1, b]
x = [1, c]
y = [1, d]
z = [1, e]

结果将是:

r = [11111, 1bcde, 11cde, 111de, 1111e, a1111, ab111, abc11, abcd1, abcde, 1b1d1, 1bc1e, 11c11, 11c1e, ... ] 

7 个答案:

答案 0 :(得分:8)

也许您正在寻找itertools.product:

#!/usr/bin/env python
import itertools
a=[1,2]
b=['a','b']
c=[str(s)+str(t) for s,t in itertools.product(a,b)]
print(c)
['1a', '1b', '2a', '2b']

v=[1,'a']
w=[1,'b']
x=[1,'c']
y=[1,'d']
z=[1,'e']

r=[''.join([str(elt) for elt in p]) for p in itertools.product(v,w,x,y,z)]
print(r)
# ['11111', '1111e', '111d1', '111de', '11c11', '11c1e', '11cd1', '11cde', '1b111', '1b11e', '1b1d1', '1b1de', '1bc11', '1bc1e', '1bcd1', '1bcde', 'a1111', 'a111e', 'a11d1', 'a11de', 'a1c11', 'a1c1e', 'a1cd1', 'a1cde', 'ab111', 'ab11e', 'ab1d1', 'ab1de', 'abc11', 'abc1e', 'abcd1', 'abcde']

请注意,产品产生2 ** 5个元素。这是你想要的吗?

itertools.product在Python 2.6中。对于以前的版本,您可以使用:

def product(*args, **kwds):
        '''
        Source: http://docs.python.org/library/itertools.html#itertools.product
        '''
        # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
        # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
        pools = map(tuple, args) * kwds.get('repeat', 1)
        result = [[]]
        for pool in pools:
            result = [x+[y] for x in result for y in pool]
        for prod in result:
            yield tuple(prod)

编辑:正如果冻指出的那样,原始问题要求使用独特的套装。如果abvwxy或{{1},则上述代码不会生成唯一集合包含重复的元素。如果这对您来说是个问题,那么您可以在将每个列表发送到itertools.product之前将其转换为集合:

z

答案 1 :(得分:2)

我不认为问题要求输入的powerset,我认为它要求(部分)输入集的笛卡尔积。如果我错了,我希望有人会纠正我。

而且,至于算法,现在您知道它正在寻找什么,Google将成为您的朋友。

在第二个示例中,您从结果集中排除了1b1de等条目。这是故意的吗?如果是故意的,那么构造输出的规则是什么?

答案 2 :(得分:2)

我认为另一个答案是为了回应:

  

我已经把它写在我的白板上了,它似乎都有一个模式,我还没有发现它。

模式。

假设您只有两个要合并的列表。您可以通过制作网格来找到所有组合。

       black        blue
     +------------+------------+
coat | black coat | blue coat  |
     +------------+------------+
hat  | black hat  | blue hat   |
     +------------+------------+

如您所见,有2 * 2种组合。如果有30种颜色和14种衣服,你将有30 * 14 = 420种组合。

随着您添加更多列表,模式会继续。而不是二维矩形,你得到一个三维的盒子数组,或最终一个 n - 维度超矩形。无论如何,组合总数始终是所有列表长度的乘积。

如果您知道有多少列表,嵌套循环是进行所有组合的自然方式。

for color in colors:
    for kind in kinds:
        print color, kind  # "black coat", "black hat", etc.

如果列表以字典顺序开头,并且没有重复项,则输出也将按字典顺序排列。

答案 3 :(得分:1)

我假设您想要笛卡尔积 - 通过从每个列表中精确选择一个元素来创建所有可能的列表。您可以递归地实现它,如下所示:

def cartesian_product(l):
    if l:
        for b in cartesian_product(l[1:]):
            for a in l[0]:
                yield [a] + b
    else:
        yield []        

l = [
 [ 'a', 'b' ],
 [ 'c', 'd', 'e' ],
 [ 'f', 'g' ],
]

for x in cartesian_product(l):
    print x

更新:~unutbu对itertools.product的建议更好,但无论如何我都会留在这里。

答案 4 :(得分:1)

由于您需要笛卡儿产品,请使用 itertools

>>> import itertools
>>> v = [1, 'a']
>>> w = [1, 'b']
>>> x = [1, 'c']
>>> y = [1, 'd']
>>> z = [1, 'e']

>>> p = [''.join(str(x) for x in c) for c in itertools.product(v,w,x,y,z)]
>>> p
['11111', '1111e', '111d1', '111de', '11c11', '11c1e', '11cd1', '11cde', '1b111'
, '1b11e', '1b1d1', '1b1de', '1bc11', '1bc1e', '1bcd1', '1bcde', 'a1111', 'a111e
', 'a11d1', 'a11de', 'a1c11', 'a1c1e', 'a1cd1', 'a1cde', 'ab111', 'ab11e', 'ab1d
1', 'ab1de', 'abc11', 'abc1e', 'abcd1', 'abcde']
>>>

答案 5 :(得分:1)

可能会这样做吗?

def getAllCombinations(listOfLists):
    if len(listOfLists) == 1:
        return [str(x) for x in listOfLists[0]]

    result = set()
    head, tail = listOfLists[0], listOfLists[1:]

    tailCombs = getAllCombinations(tail)
    for elem in head:
        for tc in tailCombs:
            result.add(str(elem) + tc)
    return result

v = [1, 'a']
w = [1, 'b']
x = [1, 'c']
y = [1, 'd']
z = [1, 'e']

>>> print getAllCombinations([v, w, x, y, z])
set(['111de', 'abc11', 'a1c1e', 'a111e', '11c11', 'ab11e', '1bc11', 'ab1d1', 'a1cd1', '1b1de', 'a11d1', '11111', '1b111', '11cd1', 'abcd1', '1bcde', 'ab111', '1bc1e', 'abc1e', '111d1', 'a1111', '11c1e', 'a1c11', '11cde', '1b11e', '1bcd1', 'abcde', 'a1cde', '1b1d1', 'a11de', 'ab1de', '1111e'])

答案 6 :(得分:0)

您正在寻找笛卡尔积。在Python中,如果你想要元组:

c = [(x, y) for x in a for y in b]
r = [(vv, ww, xx, yy, zz)
     for vv in v  for ww in w  for xx in x  for yy in y  for zz in z]