繁体   English   中英

两个列表元素的交换组合

[英]Commutative combination of elements of two lists

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

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

假设ab相同。

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

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,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')])

排序的明显差异来自于字符串和数字的不同散列。

我不认为这是最不言自明的方法,所以我不会推荐它,但为了完整起见,我会包括它。

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

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')]

np.tril_indicesk参数是一个偏移参数,因此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')

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

>>> 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')]

你是这个意思?

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')]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM