簡體   English   中英

Python 中的 Powerset 算法:列表上的 + 和 append 之間的區別

[英]Powerset algorithm in Python: difference between + and append on lists

我正在解決 Python 中的 powerset 問題。

集合 S 的冪集 P(S) 是 S 的所有子集的集合。 例如,如果S = {a, b, c}那么P(s) = {{}, {a}, {b}, {c}, {a,b}, {a, c}, {b, c}, {a, b, c}}

這個解決方案工作得很好:

def powerset(array):
    powerset = [[]]
    for num in array:
        for i in range(len(powerset)):
            curr_subset = powerset[i]
            powerset.append(curr_subset + [num])
    return powerset

但是,此解決方案不會:

def powerset(array):
    powerset = [[]]
    for num in array:
        for i in range(len(powerset)):
            curr_subset = powerset[i]
            curr_subset.append(num)
            powerset.append(curr_subset)
    return powerset

它似乎在每個 powerset.append 操作上覆蓋了 powerset 中的每個數組。 對於[1, 2, 3]的輸入,我最終得到的返回值為:

[[1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3],
 [1, 2, 2, 3, 3, 3, 3]]

知道我在這里不完全理解嗎?

您的算法的問題在於列表是可變的,並且您正在創建一個包含對同一列表的引用的列表。 任何時候您附加到其中之一,您就是附加到所有這些,因為只有其中之一。 它們都是相同的列表,您只是有多個參考。

想象一下,有一份包含 10 個某人電話號碼副本的列表; 如果你撥打第一個電話號碼並要求他們戴上帽子,那么當你撥打第二個電話號碼時,另一端的人已經戴上了帽子,因為它是同一個人。 如果您呼叫每個號碼並每次都說“戴上帽子”,那么您最終會得到一個包含 10 個電話號碼的列表,其中包含一個戴 10 個帽子的人的電話號碼,而實際上您需要 10 個戴一頂帽子的人的電話號碼。

設計這種算法最簡單的方法就是完全避免變異; 使用元組而不是列表。 這樣,每次向元組添加另一個元素時,您都是在創建一個新元組,而不是更改現有元組。

請注意,這與您使用curr_subset + [num]第一個解決方案非常相似; +操作創建一個新列表,不像append改變現有列表的狀態。

def powerset(array):
    # a list containing an empty tuple
    powerset = [()]

    for num in array:
        for i in range(len(powerset)):
            curr_subset = powerset[i]
            # append one more number to the tuple
            curr_subset += (num,)
            powerset.append(curr_subset)

    return powerset

例子:

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

暫無
暫無

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

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