ให้ชุด
{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}]
ให้ชุด
{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}]
คำตอบ:
itertools
หน้า Python มี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')]
หากคุณไม่ชอบทูเปิลว่างในตอนต้นคุณสามารถเปลี่ยนrange
คำสั่งrange(1, len(s)+1)
เพื่อหลีกเลี่ยงการรวมกันเป็น 0 ความยาว
s = list(iterable)
ต้องการ?
__len__
ใช้งาน ลองใช้powerset((n for n in range(3)))
โดยไม่ต้องตัดรายการ
powerset(range(3))
จะทำงานได้ดีแม้จะไม่มี s = list(iterable)
นี่คือรหัสเพิ่มเติมสำหรับ 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 สามารถใช้ได้ที่นี่: "ถ้าคุณไม่ชอบทูเปิลว่างที่จุดเริ่มต้นให้เปิด" คุณสามารถเปลี่ยนคำสั่ง range เป็น 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
หมายความว่าคุณไม่จำเป็นต้องคำนวณผลลัพธ์ทั้งหมดในหน่วยความจำชิ้นเดียว การคำนวณมาสก์อย่างแม่นยำนอกลูปหลักถือว่าเป็นการเพิ่มประสิทธิภาพที่คุ้มค่า
หากคุณกำลังมองหาคำตอบอย่างรวดเร็วฉันเพิ่งค้นหา "python power set" ใน google และได้สิ่งนี้: 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 powerset(lst):
return reduce(lambda result, x: result + [subset + [x] for subset in result],
lst, [[]])
มีการปรับแต่งของ 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
ฉันรู้ว่าฉันได้เพิ่มคำตอบก่อนหน้านี้แล้ว แต่ฉันชอบการใช้งานใหม่ของฉันมาก ฉันกำลังตั้งค่าเป็นอินพุต แต่จริงๆแล้วมันสามารถทำซ้ำได้และฉันกำลังส่งคืนชุดหนึ่งซึ่งเป็นชุดพลังงานของอินพุต ฉันชอบแนวทางนี้เพราะสอดคล้องกับนิยามทางคณิตศาสตร์ของเซตกำลัง ( เซตของเซตย่อยทั้งหมด ) มากกว่า
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-string ที่มีช่องว่างภายใน โดยพื้นฐานแล้วสิ่งนี้ช่วยให้ฉันสามารถเลือกองค์ประกอบที่จะเพิ่มลงในแต่ละส่วนย่อยระหว่างการทำซ้ำแต่ละครั้ง สมมติว่าชุดอินพุตมี 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 ประกอบด้วยวัตถุที่ไม่เปลี่ยนรูปเท่านั้น
คุณสามารถลดความซับซ้อนของโค้ดโดยใช้ความเข้าใจ python เพื่อกำจัดสิ่งเหล่านั้นสำหรับลูป คุณยังสามารถใช้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_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
หลักการของอัลกอริทึมนี้คือองค์ประกอบอาจมีอยู่หรือไม่มีในเซตย่อยเนื่องจากเลขฐานสองอาจเป็นหนึ่งหรือศูนย์ แต่ไม่ใช่ทั้งสองอย่าง
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 Introduction to Computational Thinking and Data Science และฉันคิดว่ามันเป็นหนึ่งในอัลกอริทึมที่ง่ายที่สุดในการทำความเข้าใจที่ฉันเคยเห็น
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]]
ตัวอย่างเช่นสมมติว่าคุณเขียนนี้แทนรหัสตัวแปรการปรับเปลี่ยนที่นำเสนอ: จากนั้นลูปจะไม่สิ้นสุด
ฉันแค่อยากจะมอบโซลูชันที่เข้าใจได้ง่ายที่สุดนั่นคือเวอร์ชันแอนตี้โค้ดกอล์ฟ
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รวมถึงรายการวิกิพีเดียในชุดไฟ
สิ่งนี้สามารถทำได้อย่างเป็นธรรมชาติด้วย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}
เพียงแค่ทบทวนชุดพลังงานอย่างรวดเร็ว!
ชุดกำลังของเซต 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
การแทนค่าเลขฐานสองของจำนวนเต็มคือ {000, 001, 010, 011, 100, 101, 110, 111} สำหรับตัวเลขตั้งแต่ 0 ถึง 7 สำหรับค่าตัวนับจำนวนเต็มให้พิจารณา 1 เป็นการรวมองค์ประกอบที่เกี่ยวข้องในคอลเลกชันและ '0' เนื่องจากการยกเว้นเราสามารถสร้างชุดย่อยตามลำดับการนับ ต้องสร้างตัวเลขจาก0
ถึงpow(2,n) -1
ที่ n คือความยาวของอาร์เรย์เช่นจำนวนบิตในการแทนค่าฐานสอง
ฟังก์ชัน Subset Generatorอย่างง่ายสามารถเขียนได้ดังต่อไปนี้ โดยพื้นฐานแล้วมันต้องอาศัย
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']]
ด้วยชุดว่างซึ่งเป็นส่วนหนึ่งของชุดย่อยทั้งหมดคุณสามารถใช้:
def subsets(iterable):
for n in range(len(iterable) + 1):
yield from combinations(iterable, n)
คำตอบเหล่านี้เกือบทั้งหมดใช้list
มากกว่าset
ซึ่งให้ความรู้สึกเหมือนเป็นการโกงสำหรับฉัน ด้วยความอยากรู้อยากเห็นฉันจึงพยายามทำเวอร์ชันง่ายๆอย่างแท้จริงset
และสรุปสำหรับคน "ใหม่สำหรับ Python" คนอื่น ๆ
ผมพบว่ามีความแปลกประหลาดคู่ในการจัดการกับงูหลามของการดำเนินงานชุด ความประหลาดใจหลักสำหรับฉันคือการจัดการชุดที่ว่างเปล่า สิ่งนี้ตรงกันข้ามกับการใช้งาน Setของ Ruby ซึ่งฉันสามารถทำได้Set[Set[]]
และได้รับSet
หนึ่งที่ว่างเปล่าSet
ดังนั้นฉันจึงพบว่าในตอนแรกมันสับสนเล็กน้อย
เพื่อตรวจสอบในการทำpowerset
กับset
s ฉันพบปัญหาสองประการ:
set()
สามารถทำซ้ำได้ดังนั้นset(set())
จะกลับมา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
ของset
ในหลามถ้าคุณต้องการที่จะเปิดเหล่านี้frozenset
s เข้าไปset
s, คุณจะต้อง map พวกเขากลับเข้ามาใน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 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)))]
; อาร์กิวเมนต์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-tuples แสดงรายการในลำดับ "พจนานุกรม" (เมื่อเราพิมพ์ตัวเลขเป็นจำนวนเต็ม) ถ้าฉันเขียนระยะห่างระหว่างตัวเลขข้างๆ (เช่นความแตกต่าง) จะแสดงจุดของฉัน:
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"]
ชัดเจนกว่าว่าเหตุใดจึงมีประโยชน์ในการรับชุดพาวเวอร์ตามลำดับนี้:
ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3
เอฟเฟกต์นี้เด่นชัดขึ้นเมื่อมีไอเท็มมากขึ้นและสำหรับจุดประสงค์ของฉันมันสร้างความแตกต่างระหว่างความสามารถในการอธิบายช่วงของดัชนีของพาวเวอร์เซตอย่างมีความหมาย
(มีเขียนโค้ดเกรย์ไว้มากมายเป็นต้นสำหรับลำดับเอาต์พุตของอัลกอริทึมใน Combinatorics ฉันไม่เห็นว่าเป็นปัญหาด้านข้าง)
จริงๆแล้วฉันเพิ่งเขียนโปรแกรมที่เกี่ยวข้องพอสมควรซึ่งใช้รหัสพาร์ติชันจำนวนเต็มอย่างรวดเร็วนี้เพื่อส่งออกค่าตามลำดับที่เหมาะสม แต่จากนั้นฉันก็ค้นพบ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)
ผมเขียนโค้ดบางส่วนร่วมมากขึ้นซึ่งจะพิมพ์ powerset อย่าง (ดู repo สำหรับฟังก์ชั่นการพิมพ์สวยฉันไม่ได้รวมอยู่ที่นี่: print_partitions
, print_partitions_by_length
และpprint_tuple
)
pset_partitions.py
ทั้งหมดนี้ค่อนข้างง่าย แต่ก็ยังอาจมีประโยชน์หากคุณต้องการโค้ดบางอย่างที่จะช่วยให้คุณเข้าถึงระดับต่างๆของพาวเวอร์เซ็ตได้โดยตรง:
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 )]
นี่คือคำตอบของฉันมันคล้ายกัน (ในเชิงแนวคิด) กับคำตอบของ lmiguelvargasf
ให้ฉันบอกว่า - [รายการคณิตศาสตร์] โดยการกำหนดพาวเวอร์เซ็ตจะมีเซตว่าง - [รสนิยมส่วนตัว] และฉันไม่ชอบใช้โฟรเซ่น
ดังนั้นอินพุตจึงเป็นรายการและผลลัพธ์จะเป็นลิสต์รายการ ฟังก์ชั่นนี้สามารถปิดได้ก่อนหน้านี้ แต่ฉันชอบองค์ประกอบของการตั้งค่าพลังงานเป็นคำสั่งตามศัพท์ซึ่งโดยพื้นฐานแล้วหมายถึงอย่างดี
def power_set(L):
"""
L is a list.
The function returns the power set, but as a list of lists.
"""
cardinality=len(L)
n=2 ** cardinality
powerset = []
for i in range(n):
a=bin(i)[2:]
subset=[]
for j in range(len(a)):
if a[-j-1]=='1':
subset.append(L[j])
powerset.append(subset)
#the function could stop here closing with
#return powerset
powerset_orderred=[]
for k in range(cardinality+1):
for w in powerset:
if len(w)==k:
powerset_orderred.append(w)
return powerset_orderred
def powerset(some_set):
res = [(a,b) for a in some_set for b in some_set]
return res