2

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

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 是笛卡尔积。我可以将它转换为一个排除身份配对的集合,但它仍然是非交换产品。

4

6 回答 6

2

假设ab是相同的。

>>> import itertools
>>> a = ["1", "2", "3"]
>>> list(itertools.combinations(a,2))
[('1', '2'), ('1', '3'), ('2', '3')]
于 2013-03-30T12:26:19.393 回答
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')]

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


好的,西奥德罗斯是对的。作为补偿,这是一个适用于任何列表列表的版本:

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)])
于 2013-03-30T12:27:45.193 回答
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')])

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

于 2013-03-30T13:02:55.127 回答
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')]

in的k参数np.tril_indices是一个偏移参数,因此k=-1意味着它不包括对角线项。

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

  1. 如果您将aand转换b为 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')
于 2019-11-17T21:08:29.550 回答
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')]
于 2019-11-17T21:29:18.850 回答
-2

你是这个意思?

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')]
于 2013-03-30T12:24:34.757 回答