Bir kümenin tüm alt kümelerini nasıl elde edebilirim? (güç seti)


103

Bir set verildi

{0, 1, 2, 3}

Alt kümeleri nasıl üretebilirim:

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

Yanıtlar:


146

Python itertoolssayfasının tam olarak bunun powersetiçin bir tarifi vardır :

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

Çıktı:

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

Başlangıçta bu boş diziyi beğenmezseniz, 0 uzunluklu bir kombinasyondan kaçınmak için rangeifadeyi değiştirebilirsiniz range(1, len(s)+1).


1
Bu, bulabildiğim en hızlı cevap, bu sayfadaki diğer bazı çözümleri Python'un timeit modülünü kullanarak bu çözümle karşılaştırarak. Bununla birlikte, bazı durumlarda, ortaya çıkan çıktıyı değiştirmeniz gerekirse (örneğin, dizeleri oluşturmak için harfleri birleştirmek), üreteçleri kullanarak özel bir reçete yazmak ve istediğiniz çıktıyı oluşturmak (örneğin, iki diziyi bir araya getirmek) çok daha hızlı olabilir.
Ceasar Bautista

neden s = list(iterable)gerekli?
Jack Stevens

@JackStevens çünkü yinelenebilir öğeler geri sarılamaz ve __len__uygulanmaları gerekmez ; powerset((n for n in range(3)))liste sarmadan deneyin .
hoefling

1
büyük dizeler için bu çok fazla hafıza tüketir!
NoobEditor

1
@AlexandreHuat: Aralıklar tembel dizilerdir, yineleyiciler değil. powerset(range(3))cezası çalışacak bile olmadans = list(iterable) .
user2357112 Monica'yı

50

İşte bir güç seti için daha fazla kod. Bu sıfırdan yazılmıştır:

>>> 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'un yorumu burada uygulanabilir: "Başlangıçta bu boş tuple'ı beğenmezseniz, on." 0 uzunluklu bir kombinasyondan kaçınmak için range ifadesini range (1, len (s) +1) olarak değiştirebilirsiniz. " benim durumlar dışında değiştirmek for i in range(1 << x)için for i in range(1, 1 << x).


Bu yıllara dönersek, şimdi şöyle yazacağım:

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]

Ve sonra test kodu şöyle görünecektir:

print(list(powerset([4, 5, 6])))

Kullanımı yield, tüm sonuçları tek bir bellek parçasında hesaplamanıza gerek olmadığı anlamına gelir. Ana döngünün dışındaki maskeleri önceden hesaplamanın değerli bir optimizasyon olduğu varsayılır.


6
Bu yaratıcı bir cevap. Ancak, onu Mark Rushakoff ile karşılaştırmak için timeit kullanarak ölçtüm ve önemli ölçüde daha yavaş olduğunu fark ettim. 16 öğeden oluşan güç setini 100 kez üretmek için, ölçümlerim 0,55'e karşılık 15,6 idi.
Ceasar Bautista

19

Hızlı bir cevap arıyorsanız, Google'da "python güç seti" aradım ve şunu buldum: Python Güç Seti Oluşturucu

İşte o sayfadaki koddan bir kopyala-yapıştır:

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

Bu şu şekilde kullanılabilir:

 l = [1, 2, 3, 4]
 r = [x for x in powerset(l)]

Şimdi r, istediğiniz tüm öğelerin bir listesidir ve sıralanabilir ve yazdırılabilir:

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
Giriş olarak boş bir dizi olması durumunda, [[][]]uzunluk kontrolü için durumları ayırmayı düzeltmek için yukarıdaki kod geri dönecektirif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
Ayush

3
Referans olarak, bunu (Ayush'un düzenlemesiyle) timeit kullanarak ölçtüm ve Mark Rushakoff'un cevabındaki güç seti tarifi ile karşılaştırdım. Benim makinemde 16 öğenin güç setini 100 kez üretmek için bu algoritma 1.36 saniye, Rushakoff ise 0.55 saniye sürdü.
Ceasar Bautista

Bunun için zaman karmaşıklığı ne olacak?
CodeQuestor

13
def powerset(lst):
    return reduce(lambda result, x: result + [subset + [x] for subset in result],
                  lst, [[]])

8

Güç kümesinde bir iyileştirme var:

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 (doğrudan Basitleştirmeye git)

Daha önce bir cevap eklediğimi biliyorum, ancak yeni uygulamamı gerçekten seviyorum. Girdi olarak bir küme alıyorum, ama aslında herhangi bir yinelenebilir olabilir ve girdinin güç kümesi olan bir dizi küme geri dönüyorum. Bu yaklaşımı seviyorum çünkü güç kümesinin matematiksel tanımıyla ( tüm alt kümelerin kümesi ) daha uyumlu .

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

Cevabınızda gönderdiğiniz çıktıyı tam olarak istiyorsanız, şunu kullanın:

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

Açıklama

Güç setinin eleman sayısının olduğu bilinmektedir 2 ** len(A), bu nedenle fordöngüde açıkça görülebilmektedir .

Girdiyi (ideal olarak bir küme) bir listeye dönüştürmem gerekiyor çünkü bir küme, benzersiz sıralanmamış öğelerin bir veri yapısıdır ve sıra, alt kümeleri oluşturmak için çok önemli olacaktır.

selectorbu algoritmanın anahtarıdır. selectorGirdi kümesiyle aynı uzunluğa sahip olduğuna dikkat edin ve bunu mümkün kılmak için dolgulu bir f-dizesi kullanmaktır. Temel olarak bu, her yineleme sırasında her alt kümeye eklenecek öğeleri seçmeme olanak tanır. Diyelim ki giriş kümesinde 3 eleman var {0, 1, 2}, bu yüzden seçici 0 ile 7 (dahil) arasında değerler alacak, bunlar ikilik tabanda:

000 # 0
001 # 1
010 # 2
011 # 3
100 # 4
101 # 5
110 # 6
111 # 7

Bu nedenle, her bit, orijinal setin bir elemanının eklenip eklenmeyeceği konusunda bir gösterge görevi görebilir. İkili sayılara bakın ve her sayıyı süper kümenin bir öğesi olarak düşünün; 1bu, dizindeki bir öğenin jeklenmesi gerektiği 0anlamına gelir ve bu öğenin eklenmemesi gerektiği anlamına gelir.

Her yinelemede bir alt küme oluşturmak için bir küme anlayışı kullanıyorum ve bu alt kümeyi frozenset,ps (güç kümesine) . Aksi takdirde, Python'daki bir küme yalnızca değişmez nesnelerden oluştuğu için onu ekleyemem.

Basitleştirme

Bazı python anlayışlarını kullanarak kodu basitleştirebilir, böylece döngüler için bunlardan kurtulabilirsiniz. Ayrıca dizini kullanmaktan zipkaçınmak için de kullanabilirsiniz jve kod aşağıdaki gibi sonlanacaktır:

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

Bu kadar. Bu algoritmadan hoşlandığım şey, diğerlerinden daha net ve sezgisel olması, çünkü itertoolsbeklendiği gibi çalışmasına rağmen güvenmek oldukça büyülü görünüyor .


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

Örneğin:

get_power_set([1,2,3])

Yol ver

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

1
Yönettiği döngüde bir döngü değişkenini ( power_set) değiştirmek çok tartışmalı bir uygulamadır. Örneğin, bunun yerine önerilen değişken değiştirerek bu kod yazdım varsayalım: power_set += [list(sub_set)+[elem]]. Sonra döngü sona ermiyor.
hughdbrown

5

Aşağıdaki algoritmayı çok açık ve basit buldum:

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

Güç kümesini oluşturmanın başka bir yolu, bitleri olan tüm ikili sayıları üretmektir n. Bir güç seti olarak nbasamaklı sayı miktarıdır 2 ^ n. Bu algoritmanın prensibi, bir elemanın bir alt kümede bulunup bulunmayacağıdır, çünkü ikili bir rakam bir veya sıfır olabilir, ancak ikisi birden olamaz.

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 Hesaplamalı Düşünme ve Veri Bilimine Giriş alırken her iki algoritmayı da buldum ve anladığım en kolay algoritmalardan biri olduğunu düşünüyorum.


3

Sadece en anlaşılır çözümü sunmak istedim, anti kod-golf versiyonu.

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

Sonuçlar

Tüm uzunluk setleri 0

[()]

Tüm uzunluk setleri 1

[('x',), ('y',), ('z',)]

Tüm uzunluk setleri 2

[('x', 'y'), ('x', 'z'), ('y', 'z')]

Tüm uzunluk setleri 3

[('x', 'y', 'z')]

Daha fazla bilgi için itertools belgelerine ve ayrıca güç kümelerindeki wikipedia girişine bakın


2

Sadece hızlı bir güç seti tazeleme!

Bir X kümesinin güç kümesi, boş küme dahil olmak üzere X'in tüm alt kümelerinin kümesidir.

Örnek X = (a, b, c) kümesi

Güç Seti = {{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}, {c}, {}}

İşte güç setini bulmanın başka bir yolu:

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

kaynağa tam kredi


2

Bu, aşağıdakilerle çok doğal bir şekilde yapılabilir 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
bu soruya verilen en zarif cevap
Arthur B.

1

Basit bir yol, tamsayıların dahili temsilini 2'nin tamamlayıcı aritmetiği altında kullanmak olabilir.

Tam sayıların ikili gösterimi, 0 ile 7 arasında değişen sayılar için {000, 001, 010, 011, 100, 101, 110, 111} şeklindedir. dışlama olarak, sayma sırasına göre alt kümeler oluşturabiliriz. Sayılar üretilen lazım 0içinpow(2,n) -1 n, ikili gösterimine bit dizisi yani sayısının uzunluğudur.

Buna dayalı basit bir Alt Küme Oluşturucu Fonksiyonu aşağıdaki gibi yazılabilir. Temelde dayanır

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

ve sonra şu şekilde kullanılabilir

def get_subsets(array):
    powerset = []
    for i in subsets(array):
        powerser.append(i)
    return powerset

Test yapmak

Yerel dosyaya aşağıdakileri ekleme

if __name__ == '__main__':
    sample = ['b',  'd',  'f']

    for i in range(len(sample)):
        print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])

aşağıdaki çıktıyı verir

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

Bu, sürdürülebilirlik veya okunabilirlik açısından pratik olmayabilir, ancak aklımı başımdan aldı. Paylaştığınız için teşekkürler, akıllı çözüm!
lorey

1

Tüm alt kümelerin bir parçası olan boş küme ile şunları kullanabilirsiniz:

def subsets(iterable):
    for n in range(len(iterable) + 1):
        yield from combinations(iterable, n)

1

Bana biraz hile gibi gelen bu yanıtların hemen hemen hepsi listyerine kullanıyor set. Bu yüzden meraktan gerçekten basit bir versiyon yapmaya setve diğer "Python'a yeni" milletler için özetlemeye çalıştım .

Python'un set uygulamasıyla uğraşırken birkaç tuhaflık olduğunu buldum . Benim için asıl sürpriz boş setlerle uğraşmaktı. Bu, Ruby'nin Set uygulamasının tam tersidir , burada basitçe yapıp Set[Set[]]bir Setiçeren boş bir tane alabilirimSet , bu yüzden başlangıçta biraz kafa karıştırıcı buldum.

İncelemek için, s powersetile yaparken setiki problemle karşılaştım:

  1. set()yinelenebilir bir alan alır, bu nedenle set(set())geri döner set() çünkü yinelenebilir boş küme boştur (sanırım :))
  2. setleri set almak, set({set()})ve set.add(set)çünkü çalışmaz set() hashable değil

Her iki sorunu da çözmek için kullandım frozenset(), bu da istediğimi tam olarak elde edemediğim anlamına geliyor ( yazım kelimenin tam anlamıyla set), ancak genel setetkileşimi kullanıyorum.

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

Aşağıda frozensetçıktı olarak 2² (16) s doğru elde ediyoruz :

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

Bir var bir yolu yoktur gibi setbir setbu çevirmek istiyorsanız, Python s frozensetiçine s sets, bir geri bunları harita gerekecek list( list(map(set, powerset(set([1,2,3,4])))) ) veya yukarıdaki değiştirin.


1

Belki soru eskiyor, ama umarım kodum birine yardımcı olur.

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, özyineleme! =)
étale-cohomology

Muhtemelen en verimli yol değil, ama yinelemeli yolu görmek her zaman ilginçtir!
Lisandro Di Meo

1

powerset()Paketin işlevini kullanın more_itertools.

Yinelenebilir tüm olası alt kümelerini verir

>>> list(powerset([1, 2, 3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

Setler istiyorsanız, şunu kullanın:

list(map(set, powerset(iterable)))

1
Pek çok insan burada tekerleği yeniden icat ediyor, IMHO bu en iyi cevaptır, çünkü pek çok ortak kitaplık, örneğin pytest tarafından gerekli olduğu için zaten bağımlılıklarınızda olabilir. libraries.io/pypi/more-itertools/dependents
lorey

1

Özyinelemeli tüm alt kümeleri alma. Çılgın tek çizgili

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 çözümüne dayalı

subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs

NameError: name 'List' is not defined
4LegsDrivenCat

@ 4LegsDrivenCat Listİthalat ekledim
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

Yalnızca kod yanıtları düşük kaliteli olarak kabul edilir: Kodunuzun ne yaptığını ve sorunu nasıl çözdüğünü açıkladığınızdan emin olun. Gönderinize daha fazla bilgi ekleyebilirseniz, soruyu soran kişiye ve gelecekteki okuyuculara yardımcı olacaktır. Tamamen kod tabanlı yanıtları açıklama
Calos

1

Bunu şu şekilde yapabilirsiniz:

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

Çıktı:

[[], [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
Bir kod çözümü gönderirken, kodun ne yaptığına ve bir sorunu çözmek için bunu veya bu yöntemi neden kullandığınıza dair ayrıntılı bir açıklama yapacak kadar nazik olmanızı önerebilir miyim? Yeni kodlayıcılar, kodun tam olarak ne yaptığını ve nedenini bilmeden sadece bir kod bloğuna bakmamalı ve onu kopyalayıp / yapıştırmamalıdır. Teşekkürler ve Stackoverflow'a hoş geldiniz.
Yokai

Gerçekten etkileyici ve özyinelemeli bir cevap.
John

1

Bunun çok geç olduğunu biliyorum

Zaten başka birçok çözüm var ama yine de ...

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

Bu çılgınca çünkü bu yanıtların hiçbiri gerçek bir Python kümesinin geri dönüşünü sağlamıyor. İşte aslında bir Python olan bir güç kümesi verecek karmaşık bir uygulama 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([]) ])

Yine de daha iyi bir uygulama görmeyi çok isterim.


İyi bir nokta, ancak OP çıktı olarak kümelerin bir listesini istiyor, bu yüzden (Python 3'te) yapabilirsiniz [*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]; eğer tercih ederseniz işlevi arg mapolabilir frozenset.
PM 2Ring

0

İşte kombinasyonları kullanan, ancak yalnızca yerleşikleri kullanan hızlı uygulamam.

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

N aralığındaki tüm alt kümeler ayarlandığı gibi:

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

Sorunun bir çeşidi, "Bilgisayar Bilimini Keşfetmek: Disiplinlerarası Problemler, İlkeler ve Python Programlama. 2015 baskısı" kitabında gördüğüm bir alıştırmadır. Bu alıştırmada 10.2.11, girdi sadece bir tam sayıdır ve çıktı, güç setleri olmalıdır. İşte benim özyinelemeli çözümüm (temel python3 dışında başka bir şey kullanmıyorum)

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

Ve çıktı

[[], [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]] Sayısı alt listeler: 16


0

İşleve rastlamadım more_itertools.powersetve bunu kullanmanızı tavsiye ederim. Ayrıca, çıkış için varsayılan sıralamayı kullanmamanızı da tavsiye ederim itertools.combinations, bunun yerine genellikle konumlar arasındaki mesafeyi en aza indirmek ve aralarında daha büyük mesafe olan öğelerin üstünde / altında daha kısa mesafe olan öğelerin alt kümelerini sıralamak istersiniz .

itertoolsSayfa tarifleri kullandığı gösterilerichain.from_iterable

  • O Not rBurada alt kısmı için standart notasyonu maçları binom katsayısı , sgenellikle olarak anılır n( “n r seç”) matematik metinlerde ve hesap makinelerinde
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))

Buradaki diğer örnekler [1,2,3,4], 2-tupleların "sözlükbilimsel" sırayla listelenmesini sağlayacak şekilde (sayıları tamsayı olarak yazdırdığımızda) güç kümesini verir. Numaraların arasındaki mesafeyi yanına yazarsam (yani farkı), bu benim noktamı gösterir:

121
132
143
231
242
341

Alt kümeler için doğru sıra, ilk olarak minimum mesafeyi 'tüketen' sıra olmalıdır, örneğin:

121
231
341
132
242
143

Burada sayıların kullanılması bu sıralamanın 'yanlış' görünmesine ["a","b","c","d"]neden olur , ancak örneğin harfleri düşünün, bu sırayla güç kümesini elde etmenin neden yararlı olabileceği daha açıktır:

ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3

Bu etki daha fazla maddeyle daha belirgindir ve benim amaçlarım için, güç kümesinin dizin aralıklarını anlamlı bir şekilde tanımlayabilmek arasındaki farkı yaratır.

( Kombinasyondaki algoritmaların çıktı sıralaması için Gray kodlar vb. Üzerine yazılmış çok şey var, bunu bir yan konu olarak görmüyorum).

Aslında, değerleri doğru sırayla çıkarmak için bu hızlı tamsayı bölümleme kodunu kullanan oldukça ilgili bir program yazdım, ancak sonra keşfettim more_itertools.powersetve çoğu kullanım için bu işlevi böyle kullanmanın muhtemelen iyi olduğunu keşfettim :

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)

(: Güzel ben buraya dahil ettik işlevleri yazdırmak için repo bakınız ben güzel POWERSET yazdırılır bazı daha karmaşık kod yazdım print_partitions, print_partitions_by_lengthve pprint_tuple).

Bunların hepsi oldukça basit, ancak güç kümesinin farklı düzeylerine doğrudan erişmenizi sağlayacak bir kod istiyorsanız yine de yararlı olabilir:

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

Örnek olarak, komut satırı argümanı olarak bir dizeyi alan bir CLI demo programı yazdım:

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

Belirli uzunlukta alt kümeler istiyorsanız, bunu şu şekilde yapabilirsiniz:

from itertools import combinations
someSet = {0, 1, 2, 3}
([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])

Daha genel olarak, isteğe bağlı uzunluk alt kümeleri için aralık düzenlemesini değiştirebilirsiniz. Çıktı

[(), (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 )]


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

6
Bu kod soruyu yanıtlayabilirken, bu kodun soruyu neden ve / veya nasıl yanıtladığına ilişkin ek bağlam sağlamak, uzun vadeli değerini artırır. Okumaya düşünün Nasıl Cevap için ve düzenleme Cevabınız onu geliştirmek için.
49'da blurfus

2
@Blurfus her zaman iyi bir uygulamadır, ancak on yıllık bir soruyu 28 başka yanıtla yanıtlarken özellikle önemlidir. Bu neden kabul edilen cevaba göre bir gelişme? Diğer cevapların sunmadığı bu cevabın katkısı nedir?
Jeremy Caney
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.