簡體   English   中英

查找列表的所有組合,每次都刪除不同的元素

[英]Find all combinations of a list with different elements removed each time

我需要一種從兩個不同的列表中查找所有組合的方法,其中每個元素可以為null,也可以不為null。 例如,對於兩個列表,我想調用一個函數,該函數返回所有這些組合的列表:

a = ['A', 'S', 'B']
b = ['A', 'B']
find_combinations(a, b)

應該返回:

[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]

我可以做這個簡單的例子,但是如果列表更復雜,例如['A', 'B', 'S', 'A', 'A']那么可能的選項就復雜得多:

[['A', 'B', 'S', 'A', 'A'],
 ['A', 'B', 'S', 'A'],
 ['A', 'B', 'S', 'A'],
 ['B', 'S', 'A', 'A']
  ... etc.

我將假設b元素是可哈希的 在這種情況下,您可以使用以下代碼:

def without(a,i,bi,l):
    if i >= len(a):
        yield tuple(l)
    else:
        l.append(a[i])
        for result in without(a,i+1,bi,l):
            yield result
        l.pop()
        if a[i] in bi:
            for result in without(a,i+1,bi,l):
                yield result

def find_combinations(a, b):
    for result in without(a,0,set(b),[]):
        yield result

在這里,我們首先將b轉換為集合以提高性能。 嚴格來說,這是沒有必要的。 然后,我們使用遞歸算法,其中對於ba中的每個元素a[i] ,我們都有一個決策點,是否將其包括在結果中(這就是為什么當該元素彈出時我們再次執行遞歸) 。 當我們到達列表的末尾時,我們將運行列表l轉換為tuple(..) 您還可以使用list(..)將其轉換為列表。

我們使用運行列表來提高性能,因為將兩個列表連接在一起是在O(n)中完成的,而運行列表可以在O(1)攤銷成本中append(..)pop(..)

這將產生一個tuple s生成器 您可以使用list(..)實現每個生成器的結果,例如:

>>> list(find_combinations(['A','S','B'],['A','B']))
[('A', 'S', 'B'), ('A', 'S'), ('S', 'B'), ('S',)]
>>> list(find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B']))
[('A', 'B', 'S', 'A', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S'), ('A', 'S', 'A', 'A'), ('A', 'S', 'A'), ('A', 'S', 'A'), ('A', 'S'), ('B', 'S', 'A', 'A'), ('B', 'S', 'A'), ('B', 'S', 'A'), ('B', 'S'), ('S', 'A', 'A'), ('S', 'A'), ('S', 'A'), ('S',)]

如果list是必需的S,你可以使用map(list,..)將它們轉換成列表,如:

>>> list(map(list,find_combinations(['A','S','B'],['A','B'])))
[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]
>>> list(map(list,find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B'])))
[['A', 'B', 'S', 'A', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S'], ['A', 'S', 'A', 'A'], ['A', 'S', 'A'], ['A', 'S', 'A'], ['A', 'S'], ['B', 'S', 'A', 'A'], ['B', 'S', 'A'], ['B', 'S', 'A'], ['B', 'S'], ['S', 'A', 'A'], ['S', 'A'], ['S', 'A'], ['S']]

玩耍后,我找到了威廉·范·昂森(Willem Van Onsem)答案的另一種方法。 不太干凈,但也可以。

def empty_derivations(rule, empty_list):
    returned = []
    returned.append(rule)
    for element in returned:
        for num, char in enumerate(element):
            temp = element[:]
            if char in empty_list:
                del temp[num]
                returned.append(temp)
    return_list = []
    for element in returned:
        if element not in return_list:
            return_list.append(element)
    return return_list

調用時給出:

>>> a = empty_derivations(['A', 'B', 'S', 'A', 'A'], ['A', 'B'])
>>> print(a)
[['A', 'B', 'S', 'A', 'A'], 
['B', 'S', 'A', 'A'], 
['A', 'S', 'A', 'A'], 
['A', 'B', 'S', 'A'], 
['S', 'A', 'A'], 
['B', 'S', 'A'], 
['A', 'S', 'A'], 
['A', 'B', 'S'], 
['S', 'A'], 
['B', 'S'], 
['A', 'S'], 
['S']]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM