Ini adalah jawaban tercepat yang dapat saya temukan, membandingkan beberapa solusi lain di halaman ini dengan yang ini menggunakan modul timeit Python. Namun, dalam kasus tertentu, jika Anda perlu memodifikasi output yang dihasilkan (misalnya menggabungkan huruf menjadi string) menulis resep khusus menggunakan generator dan membangun output yang Anda inginkan (misalnya menambahkan dua string) bisa jauh lebih cepat.
Ceasar Bautista
mengapa s = list(iterable)dibutuhkan?
Jack Stevens
@JackStevens karena iterable tidak dapat diputar ulang dan tidak perlu __len__diimplementasikan; mencoba powerset((n for n in range(3)))tanpa membungkus daftar.
hoefling
1
untuk string besar, ini akan memakan banyak memori!
NoobEditor
1
@AlexandreHuat: Rentang adalah urutan malas, bukan iterator. powerset(range(3))akan bekerja dengan baik bahkan tanpas = list(iterable) .
user2357112 mendukung Monica
54
Berikut ini lebih banyak kode untuk set kekuatan. Ini ditulis dari awal:
>>> defpowerset(s):... x = len(s)
... for i inrange(1 << x):
... print [s[j] for j inrange(x) if (i & (1 << j))]
...
>>> powerset([4,5,6])
[]
[4]
[5]
[4, 5]
[6]
[4, 6]
[5, 6]
[4, 5, 6]
Komentar Mark Rushakoff dapat diterapkan di sini: "Jika Anda tidak menyukai tupel kosong itu di awal, aktif." Anda dapat mengubah pernyataan rentang ke range (1, len (s) +1) untuk menghindari kombinasi panjang 0 ", kecuali dalam kasus saya Anda berubah for i in range(1 << x)menjadi for i in range(1, 1 << x).
Kembali ke tahun-tahun ini kemudian, saya sekarang akan menulisnya seperti ini:
defpowerset(s):
x = len(s)
masks = [1 << i for i inrange(x)]
for i inrange(1 << x):
yield [ss for mask, ss inzip(masks, s) if i & mask]
Dan kemudian kode tes akan terlihat seperti ini, katakanlah:
print(list(powerset([4, 5, 6])))
Menggunakan yieldberarti Anda tidak perlu menghitung semua hasil dalam satu bagian memori. Melakukan prakalkulasi mask di luar loop utama dianggap sebagai pengoptimalan yang bermanfaat.
Ini adalah jawaban yang kreatif. Namun, saya mengukurnya menggunakan timeit untuk membandingkannya dengan Mark Rushakoff dan memerhatikan bahwa itu jauh lebih lambat. Untuk menghasilkan set daya 16 item 100 kali, pengukuran saya adalah 0,55 versus 15,6.
Ceasar Bautista
19
Jika Anda mencari jawaban cepat, saya baru saja mencari "python power set" di google dan menemukan ini: Python Power Set Generator
Berikut adalah copy-paste dari kode di halaman itu:
defpowerset(seq):"""
Returns all the subsets of this set. This is a generator.
"""iflen(seq) <= 1:
yield seq
yield []
else:
for item in powerset(seq[1:]):
yield [seq[0]]+item
yield item
Ini bisa digunakan seperti ini:
l = [1, 2, 3, 4]
r = [x for x in powerset(l)]
Sekarang r adalah daftar semua elemen yang Anda inginkan, dan dapat disortir dan dicetak:
Dalam kasus array kosong sebagai input, kode di atas akan kembali [[][]], untuk memperbaikinya hanya memisahkan kasus untuk pemeriksaan panjangif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
Ayush
3
Sebagai referensi, saya mengukur ini (dengan suntingan Ayush) menggunakan timeit dan membandingkannya dengan resep PowerSet dalam jawaban Mark Rushakoff. Di mesin saya, untuk menghasilkan kekuatan 16 item 100 kali, algoritma ini membutuhkan 1,36 detik sementara Rushakoff membutuhkan 0,55.
Ceasar Bautista
Berapa kompleksitas waktu untuk ini?
CodeQuestor
13
defpowerset(lst):return reduce(lambda result, x: result + [subset + [x] for subset in result],
lst, [[]])
defpowerset(seq):"""
Returns all the subsets of this set. This is a generator.
"""iflen(seq) <= 0:
yield []
else:
for item in powerset(seq[1:]):
yield [seq[0]]+item
yield item
Saya tahu saya sebelumnya telah menambahkan jawaban, tetapi saya sangat menyukai implementasi baru saya. Saya mengambil satu set sebagai input, tapi sebenarnya bisa jadi iterable, dan saya mengembalikan satu set yang merupakan set daya dari input. Saya suka pendekatan ini karena lebih selaras dengan definisi matematis dari himpunan daya ( himpunan semua himpunan bagian ).
defpower_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 inrange(2 ** length):
selector = f'{i:0{length}b}'
subset = {l[j] for j, bit inenumerate(selector) if bit == '1'}
ps.add(frozenset(subset))
return ps
Jika Anda menginginkan output yang Anda posting di jawaban Anda, gunakan ini:
Diketahui bahwa jumlah elemen dari himpunan adalah 2 ** len(A), sehingga dapat dengan jelas dilihat dalam forloop.
Saya perlu mengubah masukan (idealnya satu set) menjadi daftar karena menurut satu set adalah struktur data dari elemen tak berurutan yang unik, dan urutannya akan sangat penting untuk menghasilkan himpunan bagian.
selectoradalah kunci dalam algoritma ini. Catat yang selectormemiliki panjang yang sama dengan set input, dan untuk memungkinkannya menggunakan f-string dengan padding. Pada dasarnya, ini memungkinkan saya untuk memilih elemen yang akan ditambahkan ke setiap subset selama setiap iterasi. Misalkan set input memiliki 3 elemen {0, 1, 2}, jadi selektor akan mengambil nilai antara 0 dan 7 (inklusif), yang dalam biner adalah:
Jadi, setiap bit dapat berfungsi sebagai indikator apakah elemen dari set asli harus ditambahkan atau tidak. Lihatlah bilangan biner, dan anggap saja setiap bilangan sebagai elemen dari himpunan super yang 1berarti bahwa elemen pada indeks jharus ditambahkan, dan 0berarti elemen ini tidak boleh ditambahkan.
Saya menggunakan pemahaman set untuk menghasilkan subset pada setiap iterasi, dan saya mengubah subset ini menjadi a frozensetsehingga saya dapat menambahkannya ke ps(power set). Jika tidak, saya tidak akan bisa menambahkannya karena satu set di Python hanya terdiri dari objek yang tidak bisa diubah.
Penyederhanaan
Anda dapat menyederhanakan kode menggunakan beberapa pemahaman python, sehingga Anda dapat membuangnya untuk loop. Anda juga dapat menggunakan zipuntuk menghindari penggunaan jindeks dan kode akan berakhir sebagai berikut:
defpower_set(A):
length = len(A)
return {
frozenset({e for e, b inzip(A, f'{i:{length}b}') if b == '1'})
for i inrange(2 ** length)
}
Itu dia. Yang saya suka dari algoritma ini adalah yang lebih jelas dan lebih intuitif daripada yang lain karena terlihat cukup ajaib untuk diandalkan itertoolsmeskipun berfungsi seperti yang diharapkan.
Saya menemukan algoritme berikut sangat jelas dan sederhana:
defget_powerset(some_list):"""Returns all subsets of size 0 - len(some_list) for some_list"""iflen(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_elementfor partial_subset in get_powerset(remaining_list):
subsets.append(partial_subset)
subsets.append(partial_subset[:] + [first_element])
return subsets
Cara lain untuk menghasilkan set kekuatan adalah dengan menghasilkan semua bilangan biner yang memiliki nbit. Sebagai kekuatan mengatur jumlah angka dengan ndigit 2 ^ n. Prinsip dari algoritma ini adalah bahwa suatu elemen bisa ada atau tidak dalam suatu subset karena digit biner bisa satu atau nol tapi tidak keduanya.
defpower_set(items):
N = len(items)
# enumerate the 2 ** N possible combinationsfor i inrange(2 ** N):
combo = []
for j inrange(N):
# test bit jth of integer iif (i >> j) % 2 == 1:
combo.append(items[j])
yield combo
Saya menemukan kedua algoritme tersebut ketika saya menggunakan MITx: 6.00.2x Pengantar Pemikiran Komputasi dan Ilmu Data, dan saya menganggap ini adalah salah satu algoritme termudah untuk dipahami yang pernah saya lihat.
defget_power_set(s):
power_set=[[]]
for elem in s:
# iterate over the sub sets so farfor 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
Memodifikasi variabel perulangan ( power_set) dalam perulangan yang diaturnya adalah praktik yang sangat dipertanyakan. Misalnya, Anda menulis ini bukan kode variabel-memodifikasi diusulkan: power_set += [list(sub_set)+[elem]]. Kemudian loop tidak berhenti.
hughdbrown
3
Saya hanya ingin memberikan solusi yang paling mudah dipahami, versi anti kode-golf.
from itertools import combinations
l = ["x", "y", "z", ]
defpowerset(items):
combo = []
for r inrange(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 inenumerate(l_powerset):
print"All sets of length ", i
print item
jawaban paling elegan yang diberikan untuk pertanyaan ini
Arthur
2
Hanya penyegaran set daya cepat!
Himpunan daya dari sebuah himpunan X, hanyalah himpunan dari semua himpunan bagian dari X termasuk himpunan kosong
Contoh himpunan X = (a, b, c)
Set Daya = {{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}, {c}, {}}
Berikut cara lain untuk menemukan set daya:
defpower_set(input):# returns a list of all subsets of the list aif (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]))
Cara sederhana adalah dengan memanfaatkan representasi internal bilangan bulat di bawah aritmatika komplemen 2.
Representasi biner bilangan bulat adalah sebagai {000, 001, 010, 011, 100, 101, 110, 111} untuk bilangan mulai dari 0 hingga 7. Untuk nilai penghitung bilangan bulat, mempertimbangkan 1 sebagai penyertaan elemen yang sesuai dalam kumpulan dan '0' sebagai pengecualian kita dapat menghasilkan subset berdasarkan urutan penghitungan. Nomor harus dihasilkan dari 0ke pow(2,n) -1mana n adalah panjang array jumlah yaitu bit dalam representasi biner.
Fungsi Generator Subset sederhana berdasarkan itu dapat ditulis seperti di bawah ini. Itu pada dasarnya bergantung
defsubsets(array):ifnot array:
returnelse:
length = len(array)
for max_int inrange(0x1 << length):
subset = []
for i inrange(length):
if max_int & (0x1 << i):
subset.append(array[i])
yield subset
dan kemudian bisa digunakan sebagai
defget_subsets(array):
powerset = []
for i in subsets(array):
powerser.append(i)
return powerset
Menguji
Menambahkan mengikuti di file lokal
if __name__ == '__main__':
sample = ['b', 'd', 'f']
for i inrange(len(sample)):
print"Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
memberikan hasil sebagai berikut
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']]
Hampir semua jawaban ini menggunakan listdaripada set, yang terasa seperti sedikit curang bagi saya. Jadi, karena penasaran saya mencoba membuat versi sederhana setdan merangkum untuk orang-orang "baru mengenal Python" lainnya.
Saya menemukan ada beberapa keanehan dalam menangani implementasi set Python . Kejutan utama bagi saya adalah menangani set kosong. Ini berbeda dengan implementasi Ruby Set , di mana saya dapat dengan mudah melakukan Set[Set[]]dan mendapatkan yang Setberisi kosong Set, jadi saya merasa awalnya agak membingungkan.
Untuk meninjau, saat melakukan powersetdengan sets, saya menemui dua masalah:
untuk mendapatkan satu set, set({set()})dan set.add(set)tidak akan berfungsi karena set()tidak dapat di-hash
Untuk mengatasi kedua masalah tersebut, saya memanfaatkan frozenset(), yang berarti saya tidak cukup mendapatkan apa yang saya inginkan (tipe secara harfiah set), tetapi menggunakan setantarmuka keseluruhan .
defpowerset(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
Di bawah ini kami mendapatkan 2² (16) frozensetdengan benar sebagai keluaran:
Karena tidak ada cara untuk memiliki setdari setdalam Python, jika Anda ingin mengubah ini frozensets menjadi sets, Anda harus memetakan mereka kembali ke dalam list( list(map(set, powerset(set([1,2,3,4]))))
) atau memodifikasi atas.
Begitu banyak orang yang menemukan kembali roda di sini, IMHO ini adalah jawaban terbaik karena mungkin sudah ada dalam dependensi Anda karena dibutuhkan oleh banyak pustaka umum, misalnya pytest. libraries.io/pypi/more-itertools/dependents
lorey
1
Mendapatkan semua subset dengan rekursi. Satu kalimat gila
from typing import List
defsubsets(xs: list) -> List[list]:return subsets(xs[1:]) + [x + [xs[0]] for x in subsets(xs[1:])] if xs else [[]]
@ 4LegsDrivenCat Saya telah menambahkan Listimport
Paweł Rubin
1
deffindsubsets(s, n):returnlist(itertools.combinations(s, n))
defallsubsets(s) :
a = []
for x inrange(1,len(s)+1):
a.append(map(set,findsubsets(s,x)))
return a
Jawaban hanya kode dianggap berkualitas rendah: pastikan untuk memberikan penjelasan tentang fungsi kode Anda dan bagaimana cara menyelesaikan masalah. Ini akan membantu penanya dan pembaca yang akan datang jika Anda dapat menambahkan lebih banyak informasi dalam posting Anda. Lihat Menjelaskan sepenuhnya jawaban berbasis kode
Calos
1
Anda bisa melakukannya seperti ini:
defpowerset(x):
m=[]
ifnot 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]))
Bolehkah saya menyarankan bahwa saat memposting solusi kode, berbaik hati untuk memberikan penjelasan mendetail tentang apa yang dilakukan kode tersebut dan mengapa Anda menggunakan metode ini atau itu untuk memecahkan masalah. Pembuat kode baru seharusnya tidak hanya melihat blok kode dan menyalin / menempelkannya tanpa mengetahui secara pasti apa yang dilakukan kode tersebut dan mengapa. Terima kasih dan selamat datang di Stackoverflow.
Yokai
Jawaban yang sangat mengesankan dan rekursif.
Yohanes
1
Saya tahu ini sudah terlambat
Ada banyak solusi lain tapi tetap ...
defpower_set(lst):
pw_set = [[]]
for i inrange(0,len(lst)):
for j inrange(0,len(pw_set)):
ele = pw_set[j].copy()
ele = ele + [lst[i]]
pw_set = pw_set + [ele]
return pw_set
Ini liar karena tidak ada dari jawaban ini yang benar-benar memberikan kembalinya set Python yang sebenarnya. Berikut adalah implementasi yang berantakan yang akan memberikan kekuatan yang sebenarnya adalah Python set.
Poin bagus, tetapi OP menginginkan daftar set sebagai output, jadi (dengan Python 3) Anda bisa melakukannya [*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]; fungsi arg dari mapbisa frozensetjika Anda mau.
PM 2Ring
0
Berikut adalah penerapan cepat saya yang memanfaatkan kombinasi tetapi hanya menggunakan bawaan.
defpowerSet(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 inenumerate(combo):
if val=='1':
currentSet.append(array[i])
sets.add(tuple(sorted(currentSet)))
currentSet = []
return sets
n = int(input())
l = [i for i inrange (1, n + 1)]
for number inrange(2 ** n) :
binary = bin(number)[: 1 : -1]
subset = [l[i] for i inrange(len(binary)) if binary[i] == "1"]
print(set(sorted(subset)) if number > 0else"{}")
Variasi pertanyaan tersebut, merupakan latihan yang saya lihat pada buku "Discovering Computer Science: Interdisciplinary Problems, Principles, and Python Programming. Edisi 2015". Dalam latihan 10.2.11 itu, masukannya hanyalah bilangan bulat, dan keluarannya harus set daya. Ini solusi rekursif saya (tidak menggunakan yang lain selain python3 dasar)
defpowerSetR(n):assert n >= 0if 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))
Saya belum menemukan more_itertools.powersetfungsinya dan akan merekomendasikan untuk menggunakannya. Saya juga merekomendasikan untuk tidak menggunakan pengurutan default dari output dari itertools.combinations, seringkali Anda ingin meminimalkan jarak antara posisi dan mengurutkan subset item dengan jarak yang lebih pendek di antara mereka di atas / sebelum item dengan jarak yang lebih besar di antara mereka.
Perhatikan bahwa di rsini cocok dengan notasi standar untuk bagian bawah koefisien binomial , yang sbiasanya disebut ndalam teks matematika dan pada kalkulator ("n Pilih r")
defpowerset(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 inrange(len(s)+1))
Contoh lain di sini memberikan kumpulan pangkat [1,2,3,4]sedemikian rupa sehingga 2-tupel terdaftar dalam urutan "leksikografik" (ketika kita mencetak angka sebagai bilangan bulat). Jika saya menulis jarak antara angka di sampingnya (yaitu perbedaannya), ini menunjukkan poin saya:
12 ⇒ 113 ⇒ 214 ⇒ 323 ⇒ 124 ⇒ 234 ⇒ 1
Urutan yang benar untuk subset haruslah urutan yang 'menghabiskan' jarak minimal terlebih dahulu, seperti:
12 ⇒ 123 ⇒ 134 ⇒ 113 ⇒ 224 ⇒ 214 ⇒ 3
Menggunakan angka di sini membuat urutan ini terlihat 'salah', tetapi perhatikan misalnya huruf-hurufnya ["a","b","c","d"] , lebih jelas mengapa ini mungkin berguna untuk mendapatkan set pangkat dalam urutan ini:
ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3
Efek ini lebih terasa dengan lebih banyak item, dan untuk tujuan saya, ini membuat perbedaan antara kemampuan untuk menggambarkan kisaran indeks powerset secara bermakna.
(Ada banyak yang tertulis kode Gray dll. Untuk urutan keluaran dari algoritma dalam kombinatorika, saya tidak melihatnya sebagai masalah sampingan).
Saya sebenarnya baru saja menulis program yang cukup terlibat yang menggunakan kode partisi bilangan bulat cepat ini untuk mengeluarkan nilai dalam urutan yang benar, tetapi kemudian saya menemukan more_itertools.powersetdan untuk sebagian besar penggunaan mungkin baik-baik saja untuk hanya menggunakan fungsi itu seperti:
from more_itertools import powerset
from numpy import ediff1d
defps_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)
Aku menulis beberapa kode lebih terlibat yang akan mencetak Powerset yang baik (lihat repo untuk cukup mencetak fungsi saya tidak termasuk di sini: print_partitions, print_partitions_by_length, dan pprint_tuple).
Ini semua cukup sederhana, tetapi mungkin masih berguna jika Anda menginginkan beberapa kode yang memungkinkan Anda langsung mengakses berbagai level set kekuatan:
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_10036764defasc_int_partitions(n):
a = [0for i inrange(n + 1)]
k = 1
y = n - 1while k != 0:
x = a[k - 1] + 1
k -= 1while2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1while x <= y:
a[k] = x
a[l] = y
yieldtuple(a[:k + 2])
x += 1
y -= 1
a[k] = x + y
y = x + y - 1yieldtuple(a[:k + 1])
# https://stackoverflow.com/a/6285330/2668831defuniquely_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
defsum_min(p):returnsum(p), min(p)
defpartitions_by_length(max_n, sorting=True, permuting=False):
partition_dict = {0: ()}
for n inrange(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)
ifnot sorting:
return partition_dict
for k in partition_dict:
partition_dict.update({k: sorted(partition_dict.get(k), key=sum_min)})
return partition_dict
defprint_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()
returndefgenerate_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:
# singletonsfor offset inrange(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 inenumerate(parts):
distance = sum(partition)
indices = (cumsum(partition)).tolist()
for offset inrange(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
Sebagai contoh, saya menulis program demo CLI yang mengambil string sebagai argumen baris perintah:
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, defabd, bce, cdfacd, bde, cefabe, bcfade, beface, bdfabfaefacfadfabcd, bcde, cdefabce, bcdfabde, bcefacde, bdefabcfabefadefabdfacdfacefabcde, bcdefabcdfabcefabdefacdefabcdef
Ini dia solusi saya, ini mirip (secara konseptual) dengan solusi lmiguelvargasf.
Izinkan saya mengatakan bahwa - [item matematika] menurut definisi PowerSet memang berisi set kosong - [selera pribadi] dan juga bahwa saya tidak suka menggunakan frozenset.
Jadi inputnya adalah daftar dan outputnya adalah daftar daftar. Fungsi bisa ditutup lebih awal, tapi saya suka elemen set pangkat diurutkan secara leksikografis , yang pada dasarnya berarti baik.
defpower_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 inrange(n):
a=bin(i)[2:]
subset=[]
for j inrange(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 inrange(cardinality+1):
for w in powerset:
iflen(w)==k:
powerset_orderred.append(w)
return powerset_orderred
Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan tersebut meningkatkan nilai jangka panjangnya. Pertimbangkan untuk membaca Bagaimana Menjawab dan mengedit jawaban Anda untuk memperbaikinya.
blurfus
2
Apa @blurfus selalu merupakan praktik yang baik, tetapi sangat penting ketika Anda menjawab pertanyaan satu dekade dengan 28 jawaban lainnya. Mengapa ini merupakan peningkatan dari jawaban yang diterima? Apa kontribusi jawaban ini yang tidak ditawarkan oleh jawaban lain?
Jawaban:
itertools
Halaman Python memilikipowerset
resep persis untuk ini: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))
Keluaran:
>>> 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')]
Jika Anda tidak suka tupel kosong di awal, Anda bisa mengubah
range
pernyataanrange(1, len(s)+1)
untuk menghindari kombinasi panjang 0.sumber
s = list(iterable)
dibutuhkan?__len__
diimplementasikan; mencobapowerset((n for n in range(3)))
tanpa membungkus daftar.powerset(range(3))
akan bekerja dengan baik bahkan tanpas = list(iterable)
.Berikut ini lebih banyak kode untuk set kekuatan. Ini ditulis dari awal:
>>> 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]
Komentar Mark Rushakoff dapat diterapkan di sini: "Jika Anda tidak menyukai tupel kosong itu di awal, aktif." Anda dapat mengubah pernyataan rentang ke range (1, len (s) +1) untuk menghindari kombinasi panjang 0 ", kecuali dalam kasus saya Anda berubah
for i in range(1 << x)
menjadifor i in range(1, 1 << x)
.Kembali ke tahun-tahun ini kemudian, saya sekarang akan menulisnya seperti ini:
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]
Dan kemudian kode tes akan terlihat seperti ini, katakanlah:
print(list(powerset([4, 5, 6])))
Menggunakan
yield
berarti Anda tidak perlu menghitung semua hasil dalam satu bagian memori. Melakukan prakalkulasi mask di luar loop utama dianggap sebagai pengoptimalan yang bermanfaat.sumber
Jika Anda mencari jawaban cepat, saya baru saja mencari "python power set" di google dan menemukan ini: Python Power Set Generator
Berikut adalah copy-paste dari kode di halaman itu:
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
Ini bisa digunakan seperti ini:
l = [1, 2, 3, 4] r = [x for x in powerset(l)]
Sekarang r adalah daftar semua elemen yang Anda inginkan, dan dapat disortir dan dicetak:
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]]
sumber
[[][]]
, untuk memperbaikinya hanya memisahkan kasus untuk pemeriksaan panjangif 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, [[]])
sumber
Ada penyempurnaan 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
sumber
TL; DR (langsung ke Penyederhanaan)
Saya tahu saya sebelumnya telah menambahkan jawaban, tetapi saya sangat menyukai implementasi baru saya. Saya mengambil satu set sebagai input, tapi sebenarnya bisa jadi iterable, dan saya mengembalikan satu set yang merupakan set daya dari input. Saya suka pendekatan ini karena lebih selaras dengan definisi matematis dari himpunan daya ( himpunan semua himpunan bagian ).
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
Jika Anda menginginkan output yang Anda posting di jawaban Anda, gunakan ini:
>>> [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}]
Penjelasan
Diketahui bahwa jumlah elemen dari himpunan adalah
2 ** len(A)
, sehingga dapat dengan jelas dilihat dalamfor
loop.Saya perlu mengubah masukan (idealnya satu set) menjadi daftar karena menurut satu set adalah struktur data dari elemen tak berurutan yang unik, dan urutannya akan sangat penting untuk menghasilkan himpunan bagian.
selector
adalah kunci dalam algoritma ini. Catat yangselector
memiliki panjang yang sama dengan set input, dan untuk memungkinkannya menggunakan f-string dengan padding. Pada dasarnya, ini memungkinkan saya untuk memilih elemen yang akan ditambahkan ke setiap subset selama setiap iterasi. Misalkan set input memiliki 3 elemen{0, 1, 2}
, jadi selektor akan mengambil nilai antara 0 dan 7 (inklusif), yang dalam biner adalah:000 # 0 001 # 1 010 # 2 011 # 3 100 # 4 101 # 5 110 # 6 111 # 7
Jadi, setiap bit dapat berfungsi sebagai indikator apakah elemen dari set asli harus ditambahkan atau tidak. Lihatlah bilangan biner, dan anggap saja setiap bilangan sebagai elemen dari himpunan super yang
1
berarti bahwa elemen pada indeksj
harus ditambahkan, dan0
berarti elemen ini tidak boleh ditambahkan.Saya menggunakan pemahaman set untuk menghasilkan subset pada setiap iterasi, dan saya mengubah subset ini menjadi a
frozenset
sehingga saya dapat menambahkannya keps
(power set). Jika tidak, saya tidak akan bisa menambahkannya karena satu set di Python hanya terdiri dari objek yang tidak bisa diubah.Penyederhanaan
Anda dapat menyederhanakan kode menggunakan beberapa pemahaman python, sehingga Anda dapat membuangnya untuk loop. Anda juga dapat menggunakan
zip
untuk menghindari penggunaanj
indeks dan kode akan berakhir sebagai berikut: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) }
Itu dia. Yang saya suka dari algoritma ini adalah yang lebih jelas dan lebih intuitif daripada yang lain karena terlihat cukup ajaib untuk diandalkan
itertools
meskipun berfungsi seperti yang diharapkan.sumber
Saya menemukan algoritme berikut sangat jelas dan sederhana:
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
Cara lain untuk menghasilkan set kekuatan adalah dengan menghasilkan semua bilangan biner yang memiliki
n
bit. Sebagai kekuatan mengatur jumlah angka dengann
digit2 ^ n
. Prinsip dari algoritma ini adalah bahwa suatu elemen bisa ada atau tidak dalam suatu subset karena digit biner bisa satu atau nol tapi tidak keduanya.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
Saya menemukan kedua algoritme tersebut ketika saya menggunakan MITx: 6.00.2x Pengantar Pemikiran Komputasi dan Ilmu Data, dan saya menganggap ini adalah salah satu algoritme termudah untuk dipahami yang pernah saya lihat.
sumber
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
Sebagai contoh:
get_power_set([1,2,3])
menghasilkan
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
sumber
power_set
) dalam perulangan yang diaturnya adalah praktik yang sangat dipertanyakan. Misalnya, Anda menulis ini bukan kode variabel-memodifikasi diusulkan:power_set += [list(sub_set)+[elem]]
. Kemudian loop tidak berhenti.Saya hanya ingin memberikan solusi yang paling mudah dipahami, versi anti kode-golf.
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
Hasil
Semua set panjang 0
[()]
Semua set panjang 1
[('x',), ('y',), ('z',)]
Semua set panjang 2
[('x', 'y'), ('x', 'z'), ('y', 'z')]
Semua set panjang 3
[('x', 'y', 'z')]
Untuk lebih lanjut, lihat dokumen itertools , juga entri wikipedia tentang set daya
sumber
Ini dapat dilakukan secara alami dengan
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}
sumber
Hanya penyegaran set daya cepat!
Berikut cara lain untuk menemukan set daya:
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]))
kredit penuh untuk sumber
sumber
Cara sederhana adalah dengan memanfaatkan representasi internal bilangan bulat di bawah aritmatika komplemen 2.
Representasi biner bilangan bulat adalah sebagai {000, 001, 010, 011, 100, 101, 110, 111} untuk bilangan mulai dari 0 hingga 7. Untuk nilai penghitung bilangan bulat, mempertimbangkan 1 sebagai penyertaan elemen yang sesuai dalam kumpulan dan '0' sebagai pengecualian kita dapat menghasilkan subset berdasarkan urutan penghitungan. Nomor harus dihasilkan dari
0
kepow(2,n) -1
mana n adalah panjang array jumlah yaitu bit dalam representasi biner.Fungsi Generator Subset sederhana berdasarkan itu dapat ditulis seperti di bawah ini. Itu pada dasarnya bergantung
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
dan kemudian bisa digunakan sebagai
def get_subsets(array): powerset = [] for i in subsets(array): powerser.append(i) return powerset
Menguji
Menambahkan mengikuti di file lokal
if __name__ == '__main__': sample = ['b', 'd', 'f'] for i in range(len(sample)): print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
memberikan hasil sebagai berikut
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']]
sumber
Dengan set kosong, yang merupakan bagian dari semua subset, Anda bisa menggunakan:
def subsets(iterable): for n in range(len(iterable) + 1): yield from combinations(iterable, n)
sumber
Hampir semua jawaban ini menggunakan
list
daripadaset
, yang terasa seperti sedikit curang bagi saya. Jadi, karena penasaran saya mencoba membuat versi sederhanaset
dan merangkum untuk orang-orang "baru mengenal Python" lainnya.Saya menemukan ada beberapa keanehan dalam menangani implementasi set Python . Kejutan utama bagi saya adalah menangani set kosong. Ini berbeda dengan implementasi Ruby Set , di mana saya dapat dengan mudah melakukan
Set[Set[]]
dan mendapatkan yangSet
berisi kosongSet
, jadi saya merasa awalnya agak membingungkan.Untuk meninjau, saat melakukan
powerset
denganset
s, saya menemui dua masalah:set()
mengambil iterable, jadiset(set())
akan dikembalikanset()
karena set kosong iterable kosong (ya saya kira :))set({set()})
danset.add(set)
tidak akan berfungsi karenaset()
tidak dapat di-hashUntuk mengatasi kedua masalah tersebut, saya memanfaatkan
frozenset()
, yang berarti saya tidak cukup mendapatkan apa yang saya inginkan (tipe secara harfiahset
), tetapi menggunakanset
antarmuka keseluruhan .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
Di bawah ini kami mendapatkan 2² (16)
frozenset
dengan benar sebagai keluaran: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})}
Karena tidak ada cara untuk memiliki
set
dariset
dalam Python, jika Anda ingin mengubah inifrozenset
s menjadiset
s, Anda harus memetakan mereka kembali ke dalamlist
(list(map(set, powerset(set([1,2,3,4]))))
) atau memodifikasi atas.sumber
Mungkin pertanyaannya semakin lama, tapi saya harap kode saya akan membantu seseorang.
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
sumber
Gunakan fungsi
powerset()
dari paketmore_itertools
.>>> list(powerset([1, 2, 3])) [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Jika Anda ingin set, gunakan:
list(map(set, powerset(iterable)))
sumber
Mendapatkan semua subset dengan rekursi. Satu kalimat gila
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 [[]]
Berdasarkan solusi Haskell
subsets :: [a] -> [[a]] subsets [] = [[]] subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs
sumber
NameError: name 'List' is not defined
List
importdef 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
sumber
Anda bisa melakukannya seperti ini:
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]))
Keluaran:
[[], [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]]
sumber
Saya tahu ini sudah terlambat
Ada banyak solusi lain tapi tetap ...
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
sumber
Ini liar karena tidak ada dari jawaban ini yang benar-benar memberikan kembalinya set Python yang sebenarnya. Berikut adalah implementasi yang berantakan yang akan memberikan kekuatan yang sebenarnya adalah 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([]) ])
Saya ingin melihat implementasi yang lebih baik.
sumber
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
; fungsi arg darimap
bisafrozenset
jika Anda mau.Berikut adalah penerapan cepat saya yang memanfaatkan kombinasi tetapi hanya menggunakan bawaan.
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
sumber
Semua subset dalam rentang n sebagai set:
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 "{}")
sumber
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)
sumber
Variasi pertanyaan tersebut, merupakan latihan yang saya lihat pada buku "Discovering Computer Science: Interdisciplinary Problems, Principles, and Python Programming. Edisi 2015". Dalam latihan 10.2.11 itu, masukannya hanyalah bilangan bulat, dan keluarannya harus set daya. Ini solusi rekursif saya (tidak menggunakan yang lain selain python3 dasar)
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))
Dan hasilnya adalah
[[], [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]] Jumlah sublists: 16
sumber
Saya belum menemukan
more_itertools.powerset
fungsinya dan akan merekomendasikan untuk menggunakannya. Saya juga merekomendasikan untuk tidak menggunakan pengurutan default dari output dariitertools.combinations
, seringkali Anda ingin meminimalkan jarak antara posisi dan mengurutkan subset item dengan jarak yang lebih pendek di antara mereka di atas / sebelum item dengan jarak yang lebih besar di antara mereka.The
itertools
resep Halaman menunjukkan menggunakanchain.from_iterable
r
sini cocok dengan notasi standar untuk bagian bawah koefisien binomial , yangs
biasanya disebutn
dalam teks matematika dan pada kalkulator ("n Pilih 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))
Contoh lain di sini memberikan kumpulan pangkat
[1,2,3,4]
sedemikian rupa sehingga 2-tupel terdaftar dalam urutan "leksikografik" (ketika kita mencetak angka sebagai bilangan bulat). Jika saya menulis jarak antara angka di sampingnya (yaitu perbedaannya), ini menunjukkan poin saya:12 ⇒ 1 13 ⇒ 2 14 ⇒ 3 23 ⇒ 1 24 ⇒ 2 34 ⇒ 1
Urutan yang benar untuk subset haruslah urutan yang 'menghabiskan' jarak minimal terlebih dahulu, seperti:
12 ⇒ 1 23 ⇒ 1 34 ⇒ 1 13 ⇒ 2 24 ⇒ 2 14 ⇒ 3
Menggunakan angka di sini membuat urutan ini terlihat 'salah', tetapi perhatikan misalnya huruf-hurufnya
["a","b","c","d"]
, lebih jelas mengapa ini mungkin berguna untuk mendapatkan set pangkat dalam urutan ini:ab ⇒ 1 bc ⇒ 1 cd ⇒ 1 ac ⇒ 2 bd ⇒ 2 ad ⇒ 3
Efek ini lebih terasa dengan lebih banyak item, dan untuk tujuan saya, ini membuat perbedaan antara kemampuan untuk menggambarkan kisaran indeks powerset secara bermakna.
(Ada banyak yang tertulis kode Gray dll. Untuk urutan keluaran dari algoritma dalam kombinatorika, saya tidak melihatnya sebagai masalah sampingan).
Saya sebenarnya baru saja menulis program yang cukup terlibat yang menggunakan kode partisi bilangan bulat cepat ini untuk mengeluarkan nilai dalam urutan yang benar, tetapi kemudian saya menemukan
more_itertools.powerset
dan untuk sebagian besar penggunaan mungkin baik-baik saja untuk hanya menggunakan fungsi itu seperti: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)
Aku menulis beberapa kode lebih terlibat yang akan mencetak Powerset yang baik (lihat repo untuk cukup mencetak fungsi saya tidak termasuk di sini:
print_partitions
,print_partitions_by_length
, danpprint_tuple
).pset_partitions.py
Ini semua cukup sederhana, tetapi mungkin masih berguna jika Anda menginginkan beberapa kode yang memungkinkan Anda langsung mengakses berbagai level set kekuatan:
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
Sebagai contoh, saya menulis program demo CLI yang mengambil string sebagai argumen baris perintah:
⇣
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
sumber
Jika Anda menginginkan panjang subset tertentu, Anda dapat melakukannya seperti ini:
from itertools import combinations someSet = {0, 1, 2, 3} ([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])
Secara lebih umum untuk subset panjang arbiter, Anda dapat memodifikasi arugment rentang. Outputnya adalah
[(), (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 )]
sumber
Ini dia solusi saya, ini mirip (secara konseptual) dengan solusi lmiguelvargasf.
Izinkan saya mengatakan bahwa - [item matematika] menurut definisi PowerSet memang berisi set kosong - [selera pribadi] dan juga bahwa saya tidak suka menggunakan frozenset.
Jadi inputnya adalah daftar dan outputnya adalah daftar daftar. Fungsi bisa ditutup lebih awal, tapi saya suka elemen set pangkat diurutkan secara leksikografis , yang pada dasarnya berarti baik.
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
sumber
def powerset(some_set): res = [(a,b) for a in some_set for b in some_set] return res
sumber