집합의 모든 하위 집합을 얻는 방법은 무엇입니까? (파워 셋)


103

주어진 세트

{0, 1, 2, 3}

하위 집합을 생성하려면 어떻게해야합니까?

[set(),
 {0},
 {1},
 {2},
 {3},
 {0, 1},
 {0, 2},
 {0, 3},
 {1, 2},
 {1, 3},
 {2, 3},
 {0, 1, 2},
 {0, 1, 3},
 {0, 2, 3},
 {1, 2, 3},
 {0, 1, 2, 3}]

답변:


145

Python itertools페이지 에는 정확히 이에 대한 powerset레시피가 있습니다.

from itertools import chain, combinations

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

산출:

>>> list(powerset("abcd"))
[(), ('a',), ('b',), ('c',), ('d',), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd'), ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd'), ('a', 'b', 'c', 'd')]

처음에 빈 튜플이 마음에 들지 않으면 0 길이 조합을 피하기 위해 range문을 range(1, len(s)+1)로 변경할 수 있습니다 .


1
이것은 내가 찾을 수있는 가장 빠른 대답이며,이 페이지의 다른 솔루션과 Python의 timeit 모듈을 사용하는이 솔루션을 비교합니다. 그러나 어떤 경우에는 결과 출력을 수정해야하는 경우 (예 : 문자열을 형성하기 위해 문자 결합) 생성기를 사용하여 사용자 정의 레시피를 작성하고 원하는 출력을 구축 (예 : 두 개의 문자열 추가)하는 것이 훨씬 빠를 수 있습니다.
Ceasar Bautista

s = list(iterable)필요한가요?
Jack Stevens

iterables는 되감기 할 수없고 __len__구현할 필요가 없기 때문에 @JackStevens ; powerset((n for n in range(3)))목록 포장없이 사용해보십시오 .
hoefling

1
큰 현의 경우 이것은 많은 메모리를 먹습니다!
NoobEditor

1
@AlexandreHuat : 범위는 반복기가 아니라 지연 시퀀스입니다. 없이도powerset(range(3)) 잘 작동합니다 . s = list(iterable)
user2357112는

50

다음은 powerset에 대한 추가 코드입니다. 이것은 처음부터 작성되었습니다.

>>> def powerset(s):
...     x = len(s)
...     for i in range(1 << x):
...         print [s[j] for j in range(x) if (i & (1 << j))]
...
>>> powerset([4,5,6])
[]
[4]
[5]
[4, 5]
[6]
[4, 6]
[5, 6]
[4, 5, 6]

Mark Rushakoff의 주석은 여기에 적용 할 수 있습니다. "처음에 빈 튜플이 마음에 들지 않으면 on."범위 문을 range (1, len (s) +1)로 변경하여 길이가 0 인 조합을 피할 수 있습니다. "내 경우를 제외하고는 변경 for i in range(1 << x)for i in range(1, 1 << x).


몇 년 후 다시 돌아와서 이제 다음과 같이 작성합니다.

def powerset(s):
    x = len(s)
    masks = [1 << i for i in range(x)]
    for i in range(1 << x):
        yield [ss for mask, ss in zip(masks, s) if i & mask]

그리고 테스트 코드는 다음과 같이 보일 것입니다.

print(list(powerset([4, 5, 6])))

사용 yield은 단일 메모리에서 모든 결과를 계산할 필요가 없음을 의미합니다. 메인 루프 외부에서 마스크를 미리 계산하는 것은 가치있는 최적화라고 가정합니다.


6
이것은 창의적인 대답입니다. 그러나 나는 그것을 Mark Rushakoff와 비교하기 위해 timeit을 사용하여 측정했고 그것이 상당히 느리다는 것을 알았습니다. 16 개 항목의 검정력 세트를 100 번 생성하기 위해 측정 값은 0.55 대 15.6이었습니다.
Ceasar Bautista

19

빠른 답변을 찾고 있다면 Google에서 "python power set"를 검색하여 다음을 찾았습니다. Python Power Set Generator

다음은 해당 페이지의 코드에서 복사하여 붙여 넣은 것입니다.

def powerset(seq):
    """
    Returns all the subsets of this set. This is a generator.
    """
    if len(seq) <= 1:
        yield seq
        yield []
    else:
        for item in powerset(seq[1:]):
            yield [seq[0]]+item
            yield item

다음과 같이 사용할 수 있습니다.

 l = [1, 2, 3, 4]
 r = [x for x in powerset(l)]

이제 r은 원하는 모든 요소의 목록이며 정렬 및 인쇄 할 수 있습니다.

r.sort()
print r
[[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4], [1, 3], [1, 3, 4], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]

1
입력으로 빈 배열의 경우, 위의 코드는 [[][]]길이 확인을위한 경우를 분리하기 위해를 반환합니다if len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
Ayush

3
참고로 timeit을 사용하여 이것을 (Ayush의 편집으로) 측정하고 Mark Rushakoff의 답변에있는 powerset 레시피와 비교했습니다. 내 컴퓨터에서 16 개 항목의 파워 셋을 100 번 생성하는 데이 알고리즘은 1.36 초가 걸리고 Rushakoff는 0.55 초가 걸렸습니다.
Ceasar Bautista

이것에 대한 시간 복잡성은 무엇입니까?
CodeQuestor

13
def powerset(lst):
    return reduce(lambda result, x: result + [subset + [x] for subset in result],
                  lst, [[]])

8

powerset의 개선이 있습니다.

def powerset(seq):
    """
    Returns all the subsets of this set. This is a generator.
    """
    if len(seq) <= 0:
        yield []
    else:
        for item in powerset(seq[1:]):
            yield [seq[0]]+item
            yield item

8

TL; DR (단순화로 직접 이동)

이전에 답변을 추가했지만 새로운 구현이 정말 마음에 듭니다. 나는 세트를 입력으로 취하고 있지만 실제로는 반복 가능할 수 있으며 입력의 전력 세트 인 세트 세트를 반환합니다. 나는이 접근 방식이 전력 집합 ( 모든 하위 집합 집합 ) 의 수학적 정의와 더 일치하기 때문에 좋아합니다 .

def power_set(A):
    """A is an iterable (list, tuple, set, str, etc)
    returns a set which is the power set of A."""
    length = len(A)
    l = [a for a in A]
    ps = set()

    for i in range(2 ** length):
        selector = f'{i:0{length}b}'
        subset = {l[j] for j, bit in enumerate(selector) if bit == '1'}
        ps.add(frozenset(subset))

    return ps

답변에 게시 한 출력을 정확하게 원한다면 다음을 사용하십시오.

>>> [set(s) for s in power_set({1, 2, 3, 4})]
[{3, 4},
 {2},
 {1, 4},
 {2, 3, 4},
 {2, 3},
 {1, 2, 4},
 {1, 2},
 {1, 2, 3},
 {3},
 {2, 4},
 {1},
 {1, 2, 3, 4},
 set(),
 {1, 3},
 {1, 3, 4},
 {4}]

설명

전력 집합의 요소 수는 2 ** len(A)이므로 for루프 에서 명확하게 볼 수 있습니다 .

집합에 의해 순서가 지정되지 않은 고유 한 요소의 데이터 구조이므로 입력 (이상적으로는 집합)을 목록으로 변환해야하며, 그 순서는 하위 집합을 생성하는 데 중요합니다.

selector이 알고리즘의 핵심입니다. 참고 selector입력 세트와 동일한 길이를 가지며, 그 패딩 갖는 F- 문자열을 사용이 가능하도록. 기본적으로이를 통해 각 반복 중에 각 하위 집합에 추가 할 요소를 선택할 수 있습니다. 입력 세트에 3 개의 요소가 있다고 가정 해 보겠습니다 {0, 1, 2}. 따라서 선택자는 0에서 7 (포함) 사이의 값을 가져 오며 이진법은 다음과 같습니다.

000 # 0
001 # 1
010 # 2
011 # 3
100 # 4
101 # 5
110 # 6
111 # 7

따라서 각 비트는 원래 세트의 요소를 추가해야하는지 여부를 표시기 역할을 할 수 있습니다. 이진수를보고 각 숫자를 상위 집합 1의 요소로 생각하면 인덱스에있는 요소 j가 추가 0되어야하며이 요소가 추가되지 않아야 함을 의미합니다.

집합 이해력을 사용하여 반복 할 때마다 하위 집합을 생성하고이 하위 집합을로 변환하여 frozenset추가 할 수 있습니다.ps (파워 집합)에 . 그렇지 않으면 Python의 집합이 변경 불가능한 객체로만 구성되기 때문에 추가 할 수 없습니다.

단순화

일부 파이썬 이해를 사용하여 코드를 단순화 할 수 있으므로 for 루프를 제거 할 수 있습니다. 인덱스 사용 zip을 피하는 데 사용할 수도 j있으며 코드는 다음과 같이 끝납니다.

def power_set(A):
    length = len(A)
    return {
        frozenset({e for e, b in zip(A, f'{i:{length}b}') if b == '1'})
        for i in range(2 ** length)
    }

그게 다야. 이 알고리즘에서 내가 좋아하는 것은 itertools예상대로 작동하더라도 의존하는 것이 매우 마술처럼 보이기 때문에 다른 알고리즘보다 더 명확하고 직관적이라는 것 입니다.


5
def get_power_set(s):
  power_set=[[]]
  for elem in s:
    # iterate over the sub sets so far
    for sub_set in power_set:
      # add a new subset consisting of the subset at hand added elem
      power_set=power_set+[list(sub_set)+[elem]]
  return power_set

예를 들면 :

get_power_set([1,2,3])

수율

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

1
제어하는 루프에서 루프 변수 ( power_set)를 수정하는 것은 매우 의심스러운 방법입니다. 예를 들어 제안 된 변수 수정 코드 대신 다음을 작성했다고 가정합니다 power_set += [list(sub_set)+[elem]].. 그런 다음 루프가 종료되지 않습니다.
hughdbrown

5

다음 알고리즘은 매우 명확하고 간단합니다.

def get_powerset(some_list):
    """Returns all subsets of size 0 - len(some_list) for some_list"""
    if len(some_list) == 0:
        return [[]]

    subsets = []
    first_element = some_list[0]
    remaining_list = some_list[1:]
    # Strategy: get all the subsets of remaining_list. For each
    # of those subsets, a full subset list will contain both
    # the original subset as well as a version of the subset
    # that contains first_element
    for partial_subset in get_powerset(remaining_list):
        subsets.append(partial_subset)
        subsets.append(partial_subset[:] + [first_element])

    return subsets

powerset을 생성 할 수있는 또 다른 방법은 n비트 가있는 모든 이진수를 생성하는 것 입니다. 파워 세트로 n숫자가 있는 숫자 의 양은입니다 2 ^ n. 이 알고리즘의 원리는 이진 숫자가 하나 또는 0이 될 수 있지만 둘 다가 아닐 수 있으므로 요소가 하위 집합에 존재하거나 존재하지 않을 수 있다는 것입니다.

def power_set(items):
    N = len(items)
    # enumerate the 2 ** N possible combinations
    for i in range(2 ** N):
        combo = []
        for j in range(N):
            # test bit jth of integer i
            if (i >> j) % 2 == 1:
                combo.append(items[j])
        yield combo

MITx : 6.00.2x 컴퓨터 사고 및 데이터 과학에 대한 소개를받을 때 두 가지 알고리즘을 모두 찾았으며 이것이 제가 본 것을 이해하기 가장 쉬운 알고리즘 중 하나라고 생각합니다.


3

가장 이해하기 쉬운 솔루션 인 안티 코드 골프 버전을 제공하고 싶었습니다.

from itertools import combinations

l = ["x", "y", "z", ]

def powerset(items):
    combo = []
    for r in range(len(items) + 1):
        #use a list to coerce a actual list from the combinations generator
        combo.append(list(combinations(items,r)))
    return combo

l_powerset = powerset(l)

for i, item in enumerate(l_powerset):
    print "All sets of length ", i
    print item

결과

길이 0의 모든 세트

[()]

길이 1의 모든 세트

[('x',), ('y',), ('z',)]

길이 2의 모든 세트

[('x', 'y'), ('x', 'z'), ('y', 'z')]

길이 3의 모든 세트

[('x', 'y', 'z')]

자세한 내용 은 itertools 문서 , 전원 세트 에 대한 wikipedia 항목을 참조하십시오.


2

빠른 파워 세트 리프레쉬!

집합 X의 거듭 제곱 집합은 단순히 빈 집합을 포함하여 X의 모든 하위 집합 집합입니다.

예제 세트 X = (a, b, c)

파워 세트 = {{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}, {c}, {}}

다음은 파워 세트를 찾는 또 다른 방법입니다.

def power_set(input):
    # returns a list of all subsets of the list a
    if (len(input) == 0):
        return [[]]
    else:
        main_subset = [ ]
        for small_subset in power_set(input[1:]):
            main_subset += [small_subset]
            main_subset += [[input[0]] + small_subset]
        return main_subset

print(power_set([0,1,2,3]))

소스에 대한 전체 크레딧


2

모든 하위 집합의 일부인 빈 집합을 사용하면 다음을 사용할 수 있습니다.

def subsets(iterable):
    for n in range(len(iterable) + 1):
        yield from combinations(iterable, n)

2

이것은 다음과 itertools.product같이 매우 자연스럽게 수행 될 수 있습니다 .

import itertools

def powerset(l):
    for sl in itertools.product(*[[[], [i]] for i in l]):
        yield {j for i in sl for j in i}

1
이 질문에 대한 가장 우아한 대답
Arthur B.

1

간단한 방법은 2의 보수 산술에서 정수의 내부 표현을 활용하는 것입니다.

정수의 이진 표현은 0에서 7까지의 숫자에 대해 {000, 001, 010, 011, 100, 101, 110, 111}입니다. 정수 카운터 값의 경우 1은 컬렉션에 해당 요소를 포함하고 '0'으로 간주합니다. 제외로 계수 순서를 기반으로 하위 집합을 생성 할 수 있습니다. 번호는에서에서 0까지 생성되어야 합니다.pow(2,n) -1 해당 이진 표현의 비트 수, 즉 배열의 길이이다.

이를 기반으로 한 간단한 서브셋 생성기 함수 는 다음과 같이 작성할 수 있습니다. 기본적으로

def subsets(array):
    if not array:
        return
    else:
        length = len(array)
        for max_int in range(0x1 << length):
            subset = []
            for i in range(length):
                if max_int & (0x1 << i):
                    subset.append(array[i])
            yield subset

그런 다음 다음과 같이 사용할 수 있습니다.

def get_subsets(array):
    powerset = []
    for i in subsets(array):
        powerser.append(i)
    return powerset

테스팅

로컬 파일에 다음 추가

if __name__ == '__main__':
    sample = ['b',  'd',  'f']

    for i in range(len(sample)):
        print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])

다음 출력을 제공합니다

Subsets for  ['b', 'd', 'f']  are  [[], ['b'], ['d'], ['b', 'd'], ['f'], ['b', 'f'], ['d', 'f'], ['b', 'd', 'f']]
Subsets for  ['d', 'f']  are  [[], ['d'], ['f'], ['d', 'f']]
Subsets for  ['f']  are  [[], ['f']]

이것은 유지 보수 가능성이나 가독성과 관련하여 실용적이지 않을 수 있지만 마음을 사로 잡았습니다. 공유 해주셔서 감사합니다, 스마트 솔루션!
lorey

1

이 답변의 거의 대부분은 나에게 약간의 속임수처럼 느껴지는 list대신 사용 set합니다. 그래서 호기심으로 저는 set다른 "파이썬을 처음 접하는"사람들을 위해 진정으로 간단한 버전을 만들고 요약 하려고했습니다 .

나는 파이썬의 세트 구현 을 다루는 데 몇 가지 이상한 점이 있음을 발견했습니다 . 나에게 가장 놀라운 것은 빈 세트를 다루는 것이 었습니다. 이것은 Ruby의 Set 구현 과는 대조적입니다 . 여기서는 단순히 비어있는 하나를 포함 Set[Set[]]하여 가져올 수 있으므로 처음에는 약간 혼란 스러웠습니다.SetSet

검토하기 위해 s 를 사용하는 powerset동안 set두 가지 문제가 발생했습니다.

  1. set()iterable을 취 하므로 빈 세트 iterable이 비어 있기 때문에set(set()) 반환됩니다 (duh 내가 생각합니다 :))set()
  2. 세트의 세트를 얻기 위해, set({set()})그리고 set.add(set)있기 때문에 작동하지 않습니다 set() 해쉬 아니다

두 가지 문제를 모두 해결하기 위해을 사용했습니다. 즉, frozenset()원하는 것을 얻지 못했지만 (문자 그대로 set) 전체 set인터페이스를 사용합니다.

def powerset(original_set):
  # below gives us a set with one empty set in it
  ps = set({frozenset()}) 
  for member in original_set:
    subset = set()
    for m in ps:
      # to be added into subset, needs to be
      # frozenset.union(set) so it's hashable
      subset.add(m.union(set([member]))
    ps = ps.union(subset)
  return ps

아래에서는 2² (16) frozensets를 출력으로 올바르게 얻습니다 .

In [1]: powerset(set([1,2,3,4]))
Out[2]:
{frozenset(),
 frozenset({3, 4}),
 frozenset({2}),
 frozenset({1, 4}),
 frozenset({3}),
 frozenset({2, 3}),
 frozenset({2, 3, 4}),
 frozenset({1, 2}),
 frozenset({2, 4}),
 frozenset({1}),
 frozenset({1, 2, 4}),
 frozenset({1, 3}),
 frozenset({1, 2, 3}),
 frozenset({4}),
 frozenset({1, 3, 4}),
 frozenset({1, 2, 3, 4})}

파이썬에서는 setof sets 를 가질 수있는 방법이 없기 때문에 ,이 frozensets를 sets 로 바꾸려면 다시 list( list(map(set, powerset(set([1,2,3,4])))) ) 로 매핑 하거나 위를 수정해야합니다.


1

아마도 질문이 늙어 가고 있지만 내 코드가 누군가를 도울 수 있기를 바랍니다.

def powSet(set):
    if len(set) == 0:
       return [[]]
    return addtoAll(set[0],powSet(set[1:])) + powSet(set[1:])

def addtoAll(e, set):
   for c in set:
       c.append(e)
   return set

으, 재귀! =)
étale-코호

아마도 가장 효율적인 방법은 아니지만 재귀적인 방법을 보는 것은 항상 흥미 롭습니다!
Lisandro Di Meo

1

powerset()패키지의 기능 사용more_itertools .

반복 가능한 모든 가능한 하위 집합을 생성합니다.

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

세트를 원하면 다음을 사용하십시오.

list(map(set, powerset(iterable)))

1
많은 사람들이 여기서 바퀴를 재창조하고 있습니다. IMHO 이것은 많은 공통 라이브러리 (예 : pytest)에서 필요하기 때문에 이미 종속성에있을 수 있으므로 최상의 답변입니다. libraries.io/pypi/more-itertools/dependents
lorey

1

재귀로 모든 하위 집합 가져 오기. 미친 엉덩이 한 줄

from typing import List

def subsets(xs: list) -> List[list]:
    return subsets(xs[1:]) + [x + [xs[0]] for x in subsets(xs[1:])] if xs else [[]]

Haskell 솔루션 기반

subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs

NameError: name 'List' is not defined
4LegsDrivenCat

@ 4LegsDrivenCat List가져 오기를 추가했습니다
Paweł Rubin

1
def findsubsets(s, n): 
    return list(itertools.combinations(s, n)) 

def allsubsets(s) :
    a = []
    for x in range(1,len(s)+1):
        a.append(map(set,findsubsets(s,x)))      
    return a

코드 전용 답변은 품질이 낮은 것으로 간주됩니다. 코드가 수행하는 작업과 문제를 해결하는 방법에 대한 설명을 제공해야합니다. 게시물에 더 많은 정보를 추가 할 수 있다면 질문하는 사람과 미래의 독자 모두에게 도움이 될 것입니다. 참조 전체 코드 기반의 답변을 설명하면서
Calos

1

다음과 같이 할 수 있습니다.

def powerset(x):
    m=[]
    if not x:
        m.append(x)
    else:
        A = x[0]
        B = x[1:]
        for z in powerset(B):
            m.append(z)
            r = [A] + z
            m.append(r)
    return m

print(powerset([1, 2, 3, 4]))

산출:

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

코드 솔루션을 게시 할 때 코드가 수행하는 작업과 문제를 해결하기 위해이 방법 또는 그 방법을 사용하는 이유에 대한 자세한 설명을 충분히 친절하게 제공 할 것을 제안 할 수 있습니다. 새로운 코더는 코드가 수행하는 작업과 이유를 정확히 알지 못한 채 코드 블록을보고 복사 / 붙여 넣기 만하면 안됩니다. 감사합니다. Stackoverflow에 오신 것을 환영합니다.
Yokai

정말 인상적이고 재귀적인 대답입니다.
John

1

너무 늦었다는 걸 알아

이미 많은 다른 솔루션이 있지만 여전히 ...

def power_set(lst):
    pw_set = [[]]

    for i in range(0,len(lst)):
        for j in range(0,len(pw_set)):
            ele = pw_set[j].copy()
            ele = ele + [lst[i]]
            pw_set = pw_set + [ele]

    return pw_set

0

이 답변 중 실제로 실제 Python 세트의 반환을 제공하지 않기 때문에 이것은 야생입니다. 실제로 Python 인 powerset을 제공하는 지저분한 구현이 set있습니다.

test_set = set(['yo', 'whatup', 'money'])
def powerset( base_set ):
    """ modified from pydoc's itertools recipe shown above"""
    from itertools import chain, combinations
    base_list = list( base_set )
    combo_list = [ combinations(base_list, r) for r in range(len(base_set)+1) ]

    powerset = set([])
    for ll in combo_list:
        list_of_frozensets = list( map( frozenset, map( list, ll ) ) ) 
        set_of_frozensets = set( list_of_frozensets )
        powerset = powerset.union( set_of_frozensets )

    return powerset

print powerset( test_set )
# >>> set([ frozenset(['money','whatup']), frozenset(['money','whatup','yo']), 
#        frozenset(['whatup']), frozenset(['whatup','yo']), frozenset(['yo']),
#        frozenset(['money','yo']), frozenset(['money']), frozenset([]) ])

그래도 더 나은 구현을보고 싶습니다.


좋은 지적이지만 OP는 출력으로 세트 목록을 원하므로 (Python 3에서) 할 수 있습니다 [*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]. 원하는 경우 함수 arg가 map될 수 있습니다 frozenset.
PM 2Ring

0

다음은 조합을 사용하지만 내장 기능 만 사용하는 빠른 구현입니다.

def powerSet(array):
    length = str(len(array))
    formatter = '{:0' + length + 'b}'
    combinations = []
    for i in xrange(2**int(length)):
        combinations.append(formatter.format(i))
    sets = set()
    currentSet = []
    for combo in combinations:
        for i,val in enumerate(combo):
            if val=='1':
                currentSet.append(array[i])
        sets.add(tuple(sorted(currentSet)))
        currentSet = []
    return sets

0

범위 n에있는 모든 하위 집합 :

n = int(input())
l = [i for i in range (1, n + 1)]

for number in range(2 ** n) :
    binary = bin(number)[: 1 : -1]
    subset = [l[i] for i in range(len(binary)) if binary[i] == "1"]
    print(set(sorted(subset)) if number > 0 else "{}")

0
import math    
def printPowerSet(set,set_size): 
    pow_set_size =int(math.pow(2, set_size))
    for counter in range(pow_set_size):
    for j in range(set_size):  
        if((counter & (1 << j)) > 0):
            print(set[j], end = "")
    print("")
set = ['a', 'b', 'c']
printPowerSet(set,3)

0

질문의 변형은 "Discovering Computer Science : Interdisciplinary Problems, Principles, and Python Programming. 2015 edition"이라는 책에서 볼 수있는 연습 문제입니다. 이 연습 문제 10.2.11에서 입력은 정수일 뿐이고 출력은 거듭 제곱 집합이어야합니다. 다음은 내 재귀 솔루션입니다 (기본 python3 이외의 다른 것을 사용하지 않음)

def powerSetR(n):
    assert n >= 0
    if n == 0:
        return [[]]
    else:
        input_set = list(range(1, n+1)) # [1,2,...n]
        main_subset = [ ]
        for small_subset in powerSetR(n-1):
            main_subset += [small_subset]
            main_subset += [ [input_set[-1]] + small_subset]
        return main_subset

superset = powerSetR(4)
print(superset)       
print("Number of sublists:", len(superset))

그리고 출력은

[[], [4], [3], [4, 3], [2], [4, 2], [3, 2], [4, 3, 2], [1], [4, 1 ], [3, 1], [4, 3, 1], [2, 1], [4, 2, 1], [3, 2, 1], [4, 3, 2, 1]] 개수 하위 목록 : 16


0

나는 more_itertools.powerset기능을 발견하지 못했고 그것을 사용하는 것이 좋습니다. 또한에서 출력의 기본 순서를 사용하지 않는 것이 좋습니다. itertools.combinations대신 위치 사이의 거리 를 최소화하고 항목 사이의 거리가 더 먼 항목보다 위 / 앞에있는 항목의 하위 집합을 정렬 하려는 경우가 많습니다 .

itertools페이지 조리법 이 사용하는 프로그램을chain.from_iterable

  • (가) 참고 r여기의 하부 표준 표기법 일치 이항 계수를 상기는 s일반적으로 지칭된다 n( "N R 선택 ') 수학 텍스트 및 계산기에
def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

여기에있는 다른 예 [1,2,3,4]는 2- 튜플이 "사전 식"순서로 나열되는 방식으로 의 거듭 제곱을 제공합니다 (숫자를 정수로 인쇄 할 때). 옆에있는 숫자 사이의 거리 (즉, 차이)를 쓰면 내 요점이 표시됩니다.

121
132
143
231
242
341

하위 집합의 올바른 순서는 다음과 같이 최소 거리를 먼저 '소진'하는 순서 여야합니다.

121
231
341
132
242
143

여기에서 숫자를 사용하면이 순서가 '잘못됨'으로 보이지만 예를 ["a","b","c","d"]들어이 순서로 powerset을 얻는 데 유용 할 수있는 문자 를 더 명확하게 생각해보십시오.

ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3

이 효과는 항목이 많을수록 더 두드러지며, 제 목적을 위해 파워 셋의 인덱스 범위를 의미있게 설명 할 수있는 것의 차이를 만듭니다.

( Grey 코드 에는 많은 글이 있습니다. 조합법에서 알고리즘의 출력 순서에 대해 등에 . 나는 그것을 부수적 인 문제로 보지 않습니다).

나는 실제로이 빠른 정수 파티션 코드를 사용하여 적절한 순서로 값을 출력하는 상당히 관련된 프로그램을 작성했지만, 발견 more_itertools.powerset했고 대부분의 경우 해당 함수를 다음과 같이 사용하는 것이 좋습니다.

from more_itertools import powerset
from numpy import ediff1d

def ps_sorter(tup):
    l = len(tup)
    d = ediff1d(tup).tolist()
    return l, d

ps = powerset([1,2,3,4])

ps = sorted(ps, key=ps_sorter)

for x in ps:
    print(x)

()
(1,)
(2,)
(3,)
(4,)
(1, 2)
(2, 3)
(3, 4)
(1, 3)
(2, 4)
(1, 4)
(1, 2, 3)
(2, 3, 4)
(1, 2, 4)
(1, 3, 4)
(1, 2, 3, 4)

(: 꽤 나는 여기에 포함되지했습니다 기능을 인쇄하기위한 REPO를 참조 나는 멋지게 파워 셋을 인쇄하는 몇 가지 더 복잡 코드를 작성 print_partitions, print_partitions_by_lengthpprint_tuple).

이것은 모두 매우 간단하지만 다른 수준의 powerset에 바로 액세스 할 수있는 코드를 원하는 경우 여전히 유용 할 수 있습니다.

from itertools import permutations as permute
from numpy import cumsum

# http://jeromekelleher.net/generating-integer-partitions.html
# via
# /programming/10035752/elegant-python-code-for-integer-partitioning#comment25080713_10036764

def asc_int_partitions(n):
    a = [0 for i in range(n + 1)]
    k = 1
    y = n - 1
    while k != 0:
        x = a[k - 1] + 1
        k -= 1
        while 2 * x <= y:
            a[k] = x
            y -= x
            k += 1
        l = k + 1
        while x <= y:
            a[k] = x
            a[l] = y
            yield tuple(a[:k + 2])
            x += 1
            y -= 1
        a[k] = x + y
        y = x + y - 1
        yield tuple(a[:k + 1])

# https://stackoverflow.com/a/6285330/2668831
def uniquely_permute(iterable, enforce_sort=False, r=None):
    previous = tuple()
    if enforce_sort: # potential waste of effort (default: False)
        iterable = sorted(iterable)
    for p in permute(iterable, r):
        if p > previous:
            previous = p
            yield p

def sum_min(p):
    return sum(p), min(p)

def partitions_by_length(max_n, sorting=True, permuting=False):
    partition_dict = {0: ()}
    for n in range(1,max_n+1):
        partition_dict.setdefault(n, [])
        partitions = list(asc_int_partitions(n))
        for p in partitions:
            if permuting:
                perms = uniquely_permute(p)
                for perm in perms:
                    partition_dict.get(len(p)).append(perm)
            else:
                partition_dict.get(len(p)).append(p)
    if not sorting:
        return partition_dict
    for k in partition_dict:
        partition_dict.update({k: sorted(partition_dict.get(k), key=sum_min)})
    return partition_dict

def print_partitions_by_length(max_n, sorting=True, permuting=True):
    partition_dict = partitions_by_length(max_n, sorting=sorting, permuting=permuting)
    for k in partition_dict:
        if k == 0:
            print(tuple(partition_dict.get(k)), end="")
        for p in partition_dict.get(k):
            print(pprint_tuple(p), end=" ")
        print()
    return

def generate_powerset(items, subset_handler=tuple, verbose=False):
    """
    Generate the powerset of an iterable `items`.

    Handling of the elements of the iterable is by whichever function is passed as
    `subset_handler`, which must be able to handle the `None` value for the
    empty set. The function `string_handler` will join the elements of the subset
    with the empty string (useful when `items` is an iterable of `str` variables).
    """
    ps = {0: [subset_handler()]}
    n = len(items)
    p_dict = partitions_by_length(n-1, sorting=True, permuting=True)
    for p_len, parts in p_dict.items():
        ps.setdefault(p_len, [])
        if p_len == 0:
            # singletons
            for offset in range(n):
                subset = subset_handler([items[offset]])
                if verbose:
                    if offset > 0:
                        print(end=" ")
                    if offset == n - 1:
                        print(subset, end="\n")
                    else:
                        print(subset, end=",")
                ps.get(p_len).append(subset)
        for pcount, partition in enumerate(parts):
            distance = sum(partition)
            indices = (cumsum(partition)).tolist()
            for offset in range(n - distance):
                subset = subset_handler([items[offset]] + [items[offset:][i] for i in indices])
                if verbose:
                    if offset > 0:
                        print(end=" ")
                    if offset == n - distance - 1:
                        print(subset, end="\n")
                    else:
                        print(subset, end=",")
                ps.get(p_len).append(subset)
        if verbose and p_len < n-1:
            print()
    return ps

예를 들어, 문자열을 명령 줄 인수로 사용하는 CLI 데모 프로그램을 작성했습니다.

python string_powerset.py abcdef

a, b, c, d, e, f

ab, bc, cd, de, ef
ac, bd, ce, df
ad, be, cf
ae, bf
af

abc, bcd, cde, def
abd, bce, cdf
acd, bde, cef
abe, bcf
ade, bef
ace, bdf
abf
aef
acf
adf

abcd, bcde, cdef
abce, bcdf
abde, bcef
acde, bdef
abcf
abef
adef
abdf
acdf
acef

abcde, bcdef
abcdf
abcef
abdef
acdef

abcdef

0

특정 길이의 하위 집합을 원하는 경우 다음과 같이 할 수 있습니다.

from itertools import combinations
someSet = {0, 1, 2, 3}
([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])

보다 일반적으로 임의 길이 하위 집합의 경우 범위 범위를 수정할 수 있습니다. 출력은

[(), (0,), (1,), (2,), (3,), (0, 1), (0, 2), (0, 3), (1, 2), (1 , 3), (2, 3), (0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3), (0, 1, 2, 3 )]


0
def powerset(some_set):
    res = [(a,b) for a in some_set for b in some_set]
    return res

6
이 코드는 질문에 답할 수 있지만이 코드가 질문에 대한 이유 및 / 또는 답변 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다. 답변 방법을 읽고 답변수정 하여 개선하십시오.
blurfus

2
@blurfus는 항상 좋은 습관이지만 28 개의 다른 답변으로 10 년 된 질문에 답할 때 특히 중요합니다. 이것이 허용 된 답변보다 개선 된 이유는 무엇입니까? 이 답변은 다른 답변이 제공하지 않는 무엇에 기여합니까?
Jeremy Caney

-1

Python 3.5 이상에서는 itertools.combinationsyield from 와 함께 문을 사용할 수 있습니다 .

def subsets(iterable):
    for n in range(len(iterable)):
        yield from combinations(iterable, n + 1)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.