Đưa ra một bộ
{0, 1, 2, 3}
Làm cách nào để tạo các tập hợp con:
[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}]
Đưa ra một bộ
{0, 1, 2, 3}
Làm cách nào để tạo các tập hợp con:
[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}]
Câu trả lời:
itertools
Trang Python có một powerset
công thức chính xác cho việc này:
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))
Đầu ra:
>>> 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')]
Nếu bạn không thích bộ giá trị trống đó ngay từ đầu, bạn chỉ có thể thay đổi range
câu lệnh range(1, len(s)+1)
để tránh kết hợp độ dài 0.
s = list(iterable)
cần thiết?
__len__
triển khai; thử powerset((n for n in range(3)))
mà không có gói danh sách.
powerset(range(3))
sẽ hoạt động tốt ngay cả khi không cós = list(iterable)
.
Đây là thêm mã cho bộ poweret. Điều này được viết từ đầu:
>>> 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]
Nhận xét của Mark Rushakoff có thể áp dụng ở đây: "Nếu bạn không thích bộ giá trị trống đó ngay từ đầu," bạn chỉ có thể thay đổi câu lệnh phạm vi thành phạm vi (1, len (s) +1) để tránh kết hợp độ dài 0 ", ngoại trừ trường hợp của tôi, bạn thay đổi for i in range(1 << x)
thành for i in range(1, 1 << x)
.
Quay trở lại những năm này sau đó, bây giờ tôi viết nó như thế này:
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]
Và sau đó mã kiểm tra sẽ giống như thế này, giả sử:
print(list(powerset([4, 5, 6])))
Sử dụng yield
có nghĩa là bạn không cần phải tính toán tất cả các kết quả trong một phần bộ nhớ. Tính toán trước các mặt nạ bên ngoài vòng lặp chính được coi là một cách tối ưu hóa đáng giá.
Nếu bạn đang tìm kiếm câu trả lời nhanh, tôi vừa tìm kiếm "python power set" trên google và tìm ra cái này: Python Power Set Generator
Đây là bản sao-dán từ mã trong trang đó:
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
Điều này có thể được sử dụng như thế này:
l = [1, 2, 3, 4]
r = [x for x in powerset(l)]
Bây giờ r là danh sách tất cả các phần tử bạn muốn và có thể được sắp xếp và in:
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]]
[[][]]
, để sửa chữa mà chỉ riêng các trường hợp để kiểm tra chiều dàiif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
Có một sự cải tiến của tập hợp quyền hạn:
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
Tôi biết trước đây tôi đã thêm một câu trả lời, nhưng tôi thực sự thích cách triển khai mới của mình. Tôi đang lấy một tập hợp làm đầu vào, nhưng nó thực sự có thể là bất kỳ tập hợp nào có thể lặp lại và tôi đang trả về một tập hợp các tập hợp là tập hợp sức mạnh của đầu vào. Tôi thích cách tiếp cận này vì nó phù hợp hơn với định nghĩa toán học của tập hợp lũy thừa ( tập hợp của tất cả các tập hợp con ).
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
Nếu bạn muốn chính xác kết quả mà bạn đã đăng trong câu trả lời của mình, hãy sử dụng cái này:
>>> [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}]
Người ta biết rằng số phần tử của bộ nguồn là 2 ** len(A)
, do đó có thể nhìn thấy rõ ràng trong for
vòng lặp.
Tôi cần chuyển đổi đầu vào (lý tưởng là một tập hợp) thành một danh sách bởi vì tập hợp là cấu trúc dữ liệu của các phần tử không có thứ tự duy nhất và thứ tự sẽ rất quan trọng để tạo ra các tập hợp con.
selector
là chìa khóa trong thuật toán này. Lưu ý rằng selector
có cùng độ dài với tập hợp đầu vào và để thực hiện điều này, sử dụng chuỗi f có đệm. Về cơ bản, điều này cho phép tôi chọn các phần tử sẽ được thêm vào mỗi tập hợp con trong mỗi lần lặp. Giả sử tập hợp đầu vào có 3 phần tử {0, 1, 2}
, vì vậy bộ chọn sẽ nhận các giá trị từ 0 đến 7 (bao gồm), trong hệ nhị phân là:
000 # 0
001 # 1
010 # 2
011 # 3
100 # 4
101 # 5
110 # 6
111 # 7
Vì vậy, mỗi bit có thể dùng như một chỉ báo nếu một phần tử của tập hợp ban đầu có nên được thêm vào hay không. Nhìn vào các số nhị phân và chỉ nghĩ mỗi số như một phần tử của tập siêu, trong đó 1
có nghĩa là một phần tử ở chỉ mục j
nên được thêm vào và 0
có nghĩa là phần tử này không nên được thêm vào.
Tôi đang sử dụng một tập hợp để tạo ra một tập hợp con ở mỗi lần lặp và tôi chuyển tập hợp con này thành một tập hợp con frozenset
để tôi có thể thêm nó vào ps
(tập hợp sức mạnh). Nếu không, tôi sẽ không thể thêm nó vì một tập hợp trong Python chỉ bao gồm các đối tượng bất biến.
Bạn có thể đơn giản hóa mã bằng cách sử dụng một số hiểu về python, vì vậy bạn có thể loại bỏ những vòng lặp for. Bạn cũng có thể sử dụng zip
để tránh sử dụng j
chỉ mục và mã sẽ kết thúc như sau:
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)
}
Đó là nó. Điều tôi thích ở thuật toán này là rõ ràng và trực quan hơn những thuật toán khác vì nó trông khá ảo diệu để dựa vào itertools
mặc dù nó hoạt động như mong đợi.
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
Ví dụ:
get_power_set([1,2,3])
năng suất
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
power_set
) trong vòng lặp mà nó quản lý là một thực tế rất đáng nghi ngờ. Ví dụ, giả sử bạn là người viết thay vì mã biến sửa đổi đề xuất: power_set += [list(sub_set)+[elem]]
. Sau đó, vòng lặp không kết thúc.
Tôi đã tìm thấy thuật toán sau rất rõ ràng và đơn giản:
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
Một cách khác có thể tạo ra tập lũy thừa là tạo tất cả các số nhị phân có n
bit. Như một bộ lũy thừa, số lượng có các n
chữ số là 2 ^ n
. Nguyên tắc của thuật toán này là một phần tử có thể có hoặc không trong một tập con dưới dạng chữ số nhị phân có thể là một hoặc không nhưng không phải là cả hai.
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
Tôi đã tìm thấy cả hai thuật toán khi tôi tham gia MITx: 6.00.2x Giới thiệu về Tư duy Tính toán và Khoa học Dữ liệu và tôi coi đó là một trong những thuật toán dễ hiểu nhất mà tôi từng thấy.
Tôi chỉ muốn cung cấp giải pháp dễ hiểu nhất, phiên bản chống chơi gôn.
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
Kết quả
Tất cả các bộ độ dài 0
[()]
Tất cả các bộ độ dài 1
[('x',), ('y',), ('z',)]
Tất cả các bộ chiều dài 2
[('x', 'y'), ('x', 'z'), ('y', 'z')]
Tất cả các bộ chiều dài 3
[('x', 'y', 'z')]
Để biết thêm, hãy xem tài liệu itertools , cũng là mục nhập wikipedia về bộ nguồn
Chỉ cần làm mới bộ nguồn nhanh chóng!
Tập hợp lũy thừa của một tập X, đơn giản là tập tất cả các tập con của X bao gồm cả tập rỗng
Ví dụ tập hợp X = (a, b, c)
Bộ công suất = {{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}, {c}, {}}
Đây là một cách khác để tìm bộ nguồn:
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]))
tín dụng đầy đủ cho nguồn
Với tập hợp trống, là một phần của tất cả các tập hợp con, bạn có thể sử dụng:
def subsets(iterable):
for n in range(len(iterable) + 1):
yield from combinations(iterable, n)
Điều này có thể được thực hiện rất tự nhiên với 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}
Một cách đơn giản sẽ là khai thác biểu diễn bên trong của các số nguyên dưới số học phần bù của 2.
Biểu diễn nhị phân của số nguyên là {000, 001, 010, 011, 100, 101, 110, 111} cho các số từ 0 đến 7. Đối với giá trị bộ đếm số nguyên, coi 1 là bao gồm phần tử tương ứng trong tập hợp và '0' như loại trừ, chúng ta có thể tạo các tập con dựa trên trình tự đếm. Số phải được tạo ra từ 0
để pow(2,n) -1
trong đó n là chiều dài của mảng số ví dụ của các bit trong biểu diễn nhị phân.
Hàm tạo tập hợp con đơn giản dựa trên nó có thể được viết như dưới đây. Về cơ bản nó dựa vào
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
và sau đó nó có thể được sử dụng như
def get_subsets(array):
powerset = []
for i in subsets(array):
powerser.append(i)
return powerset
Thử nghiệm
Thêm thông tin sau vào tệp cục bộ
if __name__ == '__main__':
sample = ['b', 'd', 'f']
for i in range(len(sample)):
print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
đưa ra kết quả sau
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']]
Hầu như tất cả các câu trả lời này đều sử dụng list
thay vì sử dụng set
, điều này khiến tôi cảm thấy hơi gian dối. Vì vậy, vì tò mò, tôi đã cố gắng tạo một phiên bản đơn giản thực sự set
và tóm tắt cho những người "mới làm quen với Python" khác.
Tôi nhận thấy có một vài điều kỳ lạ khi xử lý việc triển khai thiết lập của Python . Điều ngạc nhiên chính đối với tôi là xử lý các bộ trống. Điều này trái ngược với việc triển khai Ruby's Set , nơi tôi có thể đơn giản thực hiện Set[Set[]]
và lấy một cái Set
chứa trống Set
, vì vậy ban đầu tôi thấy nó hơi khó hiểu.
Để xem lại, khi thực hiện powerset
với set
s, tôi gặp phải hai vấn đề:
set()
lấy một có thể lặp lại, vì vậy set(set())
sẽ trả về set()
vì tập hợp trống có thể lặp lại là trống (tôi đoán vậy :))set({set()})
và set.add(set)
sẽ không hoạt động vì set()
không thể bămĐể giải quyết cả hai vấn đề, tôi đã sử dụng frozenset()
, có nghĩa là tôi không hoàn toàn có được những gì mình muốn (nghĩa đen là loại set
), nhưng sử dụng tổng thể set
liên kết.
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
Dưới đây, chúng tôi nhận được 2² (16) frozenset
s chính xác làm đầu ra:
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})}
Vì không có cách nào để có một set
trong số set
s trong Python, nếu bạn muốn biến những cái này frozenset
thành set
s, bạn sẽ phải ánh xạ chúng trở lại thành dấu list
( list(map(set, powerset(set([1,2,3,4]))))
) hoặc sửa đổi ở trên.
Có lẽ câu hỏi đã cũ, nhưng tôi hy vọng mã của tôi sẽ giúp được ai đó.
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
Sử dụng chức năng powerset()
từ gói more_itertools
.
Mang lại tất cả các tập con có thể lặp lại được
>>> list(powerset([1, 2, 3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Nếu bạn muốn bộ, hãy sử dụng:
list(map(set, powerset(iterable)))
Nhận tất cả các tập hợp con bằng đệ quy. Một lớp lót điên cuồng
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 [[]]
Dựa trên giải pháp Haskell
subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs
NameError: name 'List' is not defined
List
nhập
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
Bạn có thể làm như thế này:
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]))
Đầu ra:
[[], [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]]
Tôi biết điều này là quá muộn
Đã có nhiều giải pháp khác nhưng vẫn ...
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
Điều này là hoang đường vì không có câu trả lời nào trong số này thực sự cung cấp sự trở lại của một bộ Python thực. Đây là một triển khai lộn xộn sẽ cung cấp một bộ poweret thực sự là một Python 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([]) ])
Tuy nhiên, tôi muốn thấy một triển khai tốt hơn.
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
; hàm đối số của map
có thể là frozenset
nếu bạn thích.
Đây là cách triển khai nhanh chóng của tôi bằng cách sử dụng các kết hợp nhưng chỉ sử dụng các phần mềm cài sẵn.
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
Tất cả các tập con trong phạm vi n như tập hợp:
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)
Một biến thể của câu hỏi, là một bài tập tôi thấy trong sách "Khám phá Khoa học Máy tính: Các vấn đề liên ngành, các nguyên tắc và lập trình Python. Ấn bản năm 2015". Trong bài tập 10.2.11 đó, đầu vào chỉ là một số nguyên và đầu ra phải là các bộ lũy thừa. Đây là giải pháp đệ quy của tôi (không sử dụng bất kỳ thứ gì khác ngoài python3 cơ bản)
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))
Và đầu ra là
[[], [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]] danh sách phụ: 16
Tôi đã không xem qua more_itertools.powerset
chức năng và khuyên bạn nên sử dụng nó. Tôi cũng khuyên bạn không nên sử dụng thứ tự mặc định của đầu ra từ itertools.combinations
, thay vào đó, bạn thường muốn giảm thiểu khoảng cách giữa các vị trí và sắp xếp các tập hợp con của các mục có khoảng cách ngắn hơn giữa chúng ở trên / trước các mục có khoảng cách lớn hơn giữa chúng.
Các itertools
công thức trang show nó sử dụngchain.from_iterable
r
ký hiệu ở đây khớp với ký hiệu tiêu chuẩn cho phần dưới của hệ số nhị thức , s
thường được gọi là n
trong các văn bản toán học và trên máy tính ("n Chọ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))
Các ví dụ khác ở đây cung cấp tập lũy thừa [1,2,3,4]
theo cách mà 2 bộ giá trị được liệt kê theo thứ tự "từ vựng" (khi chúng tôi in các số dưới dạng số nguyên). Nếu tôi viết khoảng cách giữa các số dọc theo nó (tức là sự khác biệt), nó cho thấy quan điểm của tôi:
12 ⇒ 1
13 ⇒ 2
14 ⇒ 3
23 ⇒ 1
24 ⇒ 2
34 ⇒ 1
Thứ tự chính xác cho các tập hợp con phải là thứ tự 'sử dụng hết' khoảng cách tối thiểu trước, như sau:
12 ⇒ 1
23 ⇒ 1
34 ⇒ 1
13 ⇒ 2
24 ⇒ 2
14 ⇒ 3
Việc sử dụng các số ở đây làm cho thứ tự này trông 'sai', nhưng hãy xem xét ví dụ các chữ cái để ["a","b","c","d"]
hiểu rõ hơn lý do tại sao điều này có thể hữu ích để có được bộ poweret theo thứ tự này:
ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3
Hiệu ứng này rõ ràng hơn với nhiều mục hơn và đối với mục đích của tôi, nó tạo ra sự khác biệt giữa việc có thể mô tả phạm vi của các chỉ mục của bộ poweret một cách có ý nghĩa.
(Có rất nhiều điều được viết trên mã Gray v.v. cho thứ tự đầu ra của các thuật toán trong tổ hợp, tôi không coi đó là vấn đề phụ).
Tôi thực sự vừa viết một chương trình khá liên quan sử dụng mã phân vùng số nguyên nhanh này để xuất các giá trị theo thứ tự thích hợp, nhưng sau đó tôi đã phát hiện ra more_itertools.powerset
và đối với hầu hết các trường hợp sử dụng, có lẽ chỉ cần sử dụng hàm đó như vậy là tốt:
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)
Tôi đã viết một số mã tham gia nhiều hơn mà sẽ in Powerset độc đáo (xem repo cho các chức năng tôi đã không bao gồm ở đây khá in: print_partitions
, print_partitions_by_length
, và pprint_tuple
).
pset_partitions.py
Tất cả điều này khá đơn giản, nhưng vẫn có thể hữu ích nếu bạn muốn một số mã cho phép bạn truy cập thẳng vào các cấp độ khác nhau của bộ poweret:
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
Ví dụ, tôi đã viết một chương trình demo CLI lấy một chuỗi làm đối số dòng lệnh:
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
Nếu bạn muốn bất kỳ độ dài cụ thể nào của các tập hợp con, bạn có thể làm như sau:
from itertools import combinations
someSet = {0, 1, 2, 3}
([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])
Nói chung hơn đối với các tập con độ dài trọng tài, bạn có thể sửa đổi phạm vi cung cấp. Đầu ra là
[(), (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
Trong Python 3.5 trở lên, bạn có thể sử dụng yield from
câu lệnh cùng với itertools.combination :
def subsets(iterable):
for n in range(len(iterable)):
yield from combinations(iterable, n + 1)