两个列表的元素的交换组合

时间:2013-03-30 12:13:54

标签: python

只是一个样式问题:是否有一种内置方法可以在交换属性的断言下获得组合并排除与自身配对的元素?

a = ["1", "2", "3"]
b = ["1", "2", "3"]
seen = []
combinations = []

for v1 in a:
    for v2 in b:
        if v1 != v2:
            if (v2, v1) not in seen:
                combinations.append((v1, v2))
                seen.append((v1, v2))

>> [('1', '2'), ('1', '3'), ('2', '3')]

似乎不是非常Python。我知道itertools.product是笛卡尔积。我可以把它转换成一个排除身份配对的集合,但它仍然是非交换产品。

6 个答案:

答案 0 :(得分:2)

itertools.combinations,如果两个列表都像这里一样。 或者在一般情况下itertools.product,然后进行一些过滤:

In [7]: a = ["1", "2", "3"]
   ...: b = ["a", "b", "c"]

In [8]: list(filter(lambda t: t[0] < t[1], product(a,b)))
Out[8]: 
[('1', 'a'),
 ('1', 'b'),
 ('1', 'c'),
 ('2', 'a'),
 ('2', 'b'),
 ('2', 'c'),
 ('3', 'a'),
 ('3', 'b'),
 ('3', 'c')]

另外,我认为术语组合已经意味着结果中元素的顺序无关紧要。


好的,Theodros是对的。为了补偿,这里的版本应该适用于任何列表列表:

l = [['1','2','3'], ['a','b'], ['x','y']] 

set(tuple(sorted(p)) for p in product(*l) if len(set(p)) > 1)

给出(适当排序)

set([('1', 'a', 'x'),
     ('3', 'a', 'y'),
     ('2', 'b', 'y'),
     ('2', 'a', 'y'),
     ('1', 'a', 'y'),
     ('1', 'b', 'y'),
     ('2', 'a', 'x'),
     ('3', 'b', 'y'),
     ('1', 'b', 'x'),
     ('2', 'b', 'x'),
     ('3', 'a', 'x'),
     ('3', 'b', 'x')])

它也适用于之前的反例l = [[1,2,3], [1,3,4,5]]

set([(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (2, 4), (3, 5)])

答案 1 :(得分:1)

假设ab相同。

>>> import itertools
>>> a = ["1", "2", "3"]
>>> list(itertools.combinations(a,2))
[('1', '2'), ('1', '3'), ('2', '3')]

答案 2 :(得分:1)

如果你不关心生成的元组中的顺序没有映射到输入列表(你不关心(1,2)还是(2,1)),这将有效。在这里,您将首先获得与较小元素的组合:

a = [1,2,3]
b = [1,3,4,5]

set([(min(x,y), max(x,y)) for x in a for y in b if x != y])

给出

set([(1, 2),
     (1, 3),
     (1, 4),
     (1, 5),
     (2, 3),
     (2, 5),
     (3, 4),
     (2, 4),
     (3, 5)])

使用字符串

a = '1 2 3'.split()
b = '1 3 4 5'.split()

你得到了

set([('2', '3'),
     ('3', '5'),
     ('1', '4'),
     ('3', '4'),
     ('1', '5'),
     ('1', '2'),
     ('2', '5'),
     ('1', '3'),
     ('2', '4')])

顺序的明显差异来自字符串和数字的不同哈希值。

答案 3 :(得分:0)

我不认为这是最不言自明的方式,因此我不推荐这样做,但出于完整性考虑,我将其包括在内。

利用交换对是由两个数组的乘积生成的矩阵的上下三角形这一事实。

numpy函数np.tril_indices返回一个元组,其中仅包含数组下三角的索引。

  1. 获取所有不包括交换对的产品(根据需要),但包括与自身配对的元素(不是所需的产品):
>>> import numpy as np
>>> n_vars = len(a)
>>> assert len(b) == n_vars  # Only works if len(a) == len(b)
>>> [(a[i], b[j]) for i, j in zip(*np.tril_indices(n_vars))]
[('1', '1'), ('2', '1'), ('2', '2'), ('3', '1'), ('3', '2'), ('3', '3')]
  1. 排除与自身配对的元素(您想要的):
>>> [(a[i], b[j]) for i, j in zip(*np.tril_indices(n_vars, k=-1))]
[('2', '1'), ('3', '1'), ('3', '2')]

k中的np.tril_indices参数是一个偏移量参数,因此k=-1表示它不包括对角线项。

由于它是一个numpy函数,因此可能非常快。

  1. 如果将ab转换为numpy数组,也可以执行以下操作:
>>> a = np.array(a)
>>> b = np.array(b)
>>> ind = np.tril_indices(n_vars, k=-1)
>>> list(zip(a[ind[0]], b[ind[1]]))
[('2', '1'), ('3', '1'), ('3', '2')]
>>> np.stack([a[ind[0]], b[ind[1]]]).T
array([['2', '1'],
       ['3', '1'],
       ['3', '2']], dtype='<U1')

答案 4 :(得分:0)

我认为可能是最简单,最明确的(即不言自明的)解决方案:

>>> for i in range(len(a)): 
...     for j in range(i+1, len(b)): 
...         print(a[i], a[j]) 
... 
1 2
1 3
2 3

除非您在内部循环中执行的操作非常快,否则python for循环的效率低下几乎不会成为瓶颈。

或者,这个:

>>> [(a[i], b[j]) for i in range(len(a)) for j in range(i+1, len(b))]
[('1', '2'), ('1', '3'), ('2', '3')]

答案 5 :(得分:-1)

你的意思是?

a = ["1", "2", "3"]
b = ["1", "2", "3"]
print [(x,y) for x in a for y in b]

输出:

[('1', '1'), ('1', '2'), ('1', '3'), ('2', '1'), ('2', '2'), ('2', '3'), ('3', '1'), ('3', '2'), ('3', '3')]