Bagaimana cara mendapatkan semua subset dari satu set? (PowerSet)


109

Diberikan satu set

{0, 1, 2, 3}

Bagaimana saya bisa menghasilkan subset:

[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}]

Apa aplikasi PowerSet?
X10D

Jawaban:


150

itertoolsHalaman Python memiliki powersetresep 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 rangepernyataan range(1, len(s)+1)untuk menghindari kombinasi panjang 0.


1
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:

>>> 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)menjadi for 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 yieldberarti Anda tidak perlu menghitung semua hasil dalam satu bagian memori. Melakukan prakalkulasi mask di luar loop utama dianggap sebagai pengoptimalan yang bermanfaat.


6
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:

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]]

1
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
def powerset(lst):
    return reduce(lambda result, x: result + [subset + [x] for subset in result],
                  lst, [[]])

9

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

8

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 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:

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 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:

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 itertoolsmeskipun berfungsi seperti yang diharapkan.


7

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 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.

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.


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

Sebagai contoh:

get_power_set([1,2,3])

menghasilkan

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

2
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", ]

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


3

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}

1
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:

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


1

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

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']]

Ini mungkin tidak praktis dalam hal pemeliharaan atau keterbacaan, tetapi itu mengejutkan saya. Terima kasih telah berbagi, solusi cerdas!
lorey

1

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)

1

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:

  1. set()mengambil iterable, jadi set(set())akan dikembalikan set() karena set kosong iterable kosong (ya saya kira :))
  2. 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 .

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) frozensetdengan 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 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.


1

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

ew, rekursi! =)
étale-cohomology

Mungkin bukan cara yang paling efisien, tetapi selalu menarik untuk melihat cara rekursif!
Lisandro Di Meo

1

Gunakan fungsi powerset()dari paket more_itertools.

Menghasilkan semua subset yang mungkin dari iterable

>>> 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)))

1
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

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

NameError: name 'List' is not defined
4LegsDrivenCat

@ 4LegsDrivenCat Saya telah menambahkan Listimport
Paweł Rubin

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

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

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:

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]]

1
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 ...

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

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

    return pw_set

0

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.


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.

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

0

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 "{}")

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

0

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


0

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.

The itertoolsresep Halaman menunjukkan menggunakanchain.from_iterable

  • 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")
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:

121
132
143
231
242
341

Urutan yang benar untuk subset haruslah urutan yang 'menghabiskan' jarak minimal terlebih dahulu, seperti:

121
231
341
132
242
143

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

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, 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_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:

python string_powerset.py abcdef

a, b, c, d, e, f

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

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

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

abcde, bcdef
abcdf
abcef
abdef
acdef

abcdef

0

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 )]


0

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

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

6
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?
Jeremy Caney
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.