簡體   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