주어진 세트
{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}]
답변:
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)
로 변경할 수 있습니다 .
s = list(iterable)
필요한가요?
__len__
구현할 필요가 없기 때문에 @JackStevens ; powerset((n for n in range(3)))
목록 포장없이 사용해보십시오 .
다음은 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
은 단일 메모리에서 모든 결과를 계산할 필요가 없음을 의미합니다. 메인 루프 외부에서 마스크를 미리 계산하는 것은 가치있는 최적화라고 가정합니다.
빠른 답변을 찾고 있다면 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]]
[[][]]
길이 확인을위한 경우를 분리하기 위해를 반환합니다if len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
이전에 답변을 추가했지만 새로운 구현이 정말 마음에 듭니다. 나는 세트를 입력으로 취하고 있지만 실제로는 반복 가능할 수 있으며 입력의 전력 세트 인 세트 세트를 반환합니다. 나는이 접근 방식이 전력 집합 ( 모든 하위 집합 집합 ) 의 수학적 정의와 더 일치하기 때문에 좋아합니다 .
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
예상대로 작동하더라도 의존하는 것이 매우 마술처럼 보이기 때문에 다른 알고리즘보다 더 명확하고 직관적이라는 것 입니다.
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]]
power_set
)를 수정하는 것은 매우 의심스러운 방법입니다. 예를 들어 제안 된 변수 수정 코드 대신 다음을 작성했다고 가정합니다 power_set += [list(sub_set)+[elem]]
.. 그런 다음 루프가 종료되지 않습니다.
다음 알고리즘은 매우 명확하고 간단합니다.
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 컴퓨터 사고 및 데이터 과학에 대한 소개를받을 때 두 가지 알고리즘을 모두 찾았으며 이것이 제가 본 것을 이해하기 가장 쉬운 알고리즘 중 하나라고 생각합니다.
가장 이해하기 쉬운 솔루션 인 안티 코드 골프 버전을 제공하고 싶었습니다.
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 항목을 참조하십시오.
빠른 파워 세트 리프레쉬!
집합 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의 보수 산술에서 정수의 내부 표현을 활용하는 것입니다.
정수의 이진 표현은 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']]
이 답변의 거의 대부분은 나에게 약간의 속임수처럼 느껴지는 list
대신 사용 set
합니다. 그래서 호기심으로 저는 set
다른 "파이썬을 처음 접하는"사람들을 위해 진정으로 간단한 버전을 만들고 요약 하려고했습니다 .
나는 파이썬의 세트 구현 을 다루는 데 몇 가지 이상한 점이 있음을 발견했습니다 . 나에게 가장 놀라운 것은 빈 세트를 다루는 것이 었습니다. 이것은 Ruby의 Set 구현 과는 대조적입니다 . 여기서는 단순히 비어있는 하나를 포함 Set[Set[]]
하여 가져올 수 있으므로 처음에는 약간 혼란 스러웠습니다.Set
Set
검토하기 위해 s 를 사용하는 powerset
동안 set
두 가지 문제가 발생했습니다.
set()
iterable을 취 하므로 빈 세트 iterable이 비어 있기 때문에set(set())
반환됩니다 (duh 내가 생각합니다 :))set()
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) frozenset
s를 출력으로 올바르게 얻습니다 .
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})}
파이썬에서는 set
of set
s 를 가질 수있는 방법이 없기 때문에 ,이 frozenset
s를 set
s 로 바꾸려면 다시 list
( list(map(set, powerset(set([1,2,3,4]))))
) 로 매핑 하거나 위를 수정해야합니다.
아마도 질문이 늙어 가고 있지만 내 코드가 누군가를 도울 수 있기를 바랍니다.
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
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)))
재귀로 모든 하위 집합 가져 오기. 미친 엉덩이 한 줄
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
List
가져 오기를 추가했습니다
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
다음과 같이 할 수 있습니다.
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]]
너무 늦었다는 걸 알아
이미 많은 다른 솔루션이 있지만 여전히 ...
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
이 답변 중 실제로 실제 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([]) ])
그래도 더 나은 구현을보고 싶습니다.
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
. 원하는 경우 함수 arg가 map
될 수 있습니다 frozenset
.
다음은 조합을 사용하지만 내장 기능 만 사용하는 빠른 구현입니다.
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
범위 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 "{}")
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)
질문의 변형은 "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
나는 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- 튜플이 "사전 식"순서로 나열되는 방식으로 의 거듭 제곱을 제공합니다 (숫자를 정수로 인쇄 할 때). 옆에있는 숫자 사이의 거리 (즉, 차이)를 쓰면 내 요점이 표시됩니다.
12 ⇒ 1
13 ⇒ 2
14 ⇒ 3
23 ⇒ 1
24 ⇒ 2
34 ⇒ 1
하위 집합의 올바른 순서는 다음과 같이 최소 거리를 먼저 '소진'하는 순서 여야합니다.
12 ⇒ 1
23 ⇒ 1
34 ⇒ 1
13 ⇒ 2
24 ⇒ 2
14 ⇒ 3
여기에서 숫자를 사용하면이 순서가 '잘못됨'으로 보이지만 예를 ["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_length
및 pprint_tuple
).
pset_partitions.py
이것은 모두 매우 간단하지만 다른 수준의 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
특정 길이의 하위 집합을 원하는 경우 다음과 같이 할 수 있습니다.
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 )]
def powerset(some_set):
res = [(a,b) for a in some_set for b in some_set]
return res
Python 3.5 이상에서는 itertools.combinationsyield from
와 함께 문을 사용할 수 있습니다 .
def subsets(iterable):
for n in range(len(iterable)):
yield from combinations(iterable, n + 1)