python set powerset

python - ¿Cuál es una buena manera de combinar a través de un conjunto?



set powerset (11)

Aquí está mi implementación rápida utilizando combinaciones pero usando solo complementos.

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

Dado un conjunto

{a,b,c,d}

¿Cuál es una buena manera de producir

{a,b,c,d,ab,ac,ad,bc,bd,cd,abc,abd,bcd,abcd}

?


Aquí hay más código para un powerset. Esto está escrito desde cero:

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

El comentario de Mark Rushakoff es aplicable aquí: "Si no te gusta esa tupla vacía al principio, adelante", puedes simplemente cambiar la declaración de rango a rango (1, len (s) +1) para evitar una combinación de 0 de longitud ", excepto en mi caso cambias for i in range(1 << x) a for i in range(1, 1 << x) .

Volviendo a esto años después, ahora lo escribiría así:

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]

Y luego el código de prueba se vería así, por ejemplo:

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

Usar el yield significa que no necesita calcular todos los resultados en una sola pieza de memoria. Se supone que el precalculo de las máscaras fuera del ciclo principal es una optimización que vale la pena.


Esto es salvaje porque ninguna de estas respuestas realmente proporciona el retorno de un conjunto de Python real. Aquí hay una implementación desordenada que dará un conjunto de poder que en realidad es un set Python.

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

Aunque me encantaría ver una mejor implementación.


Hay un refinamiento de 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


He encontrado el siguiente algoritmo muy claro y simple:

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_all_subsets(remaining_list): subsets.append(partial_subset) subsets.append(partial_subset[:] + [first_element]) return subsets

Otra forma en que uno puede generar el conjunto de poder es generando todos los números binarios que tienen n bits. Como potencia establecida, la cantidad de números con n dígitos es 2 ^ n . El principio de este algoritmo es que un elemento podría estar presente o no en un subconjunto, ya que un dígito binario podría ser uno o cero, pero no ambos.

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

Encontré ambos algoritmos cuando estaba tomando MITx: 6.00.2x Introducción al pensamiento computacional y ciencia de datos, y considero que es uno de los algoritmos más fáciles de entender que he visto.


La página de itertools Python tiene exactamente una receta de powerset para esto:

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

Salida:

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

Si no le gusta esa tupla vacía al principio, puede simplemente cambiar la declaración de range(1, len(s)+1) a range(1, len(s)+1) para evitar una combinación de 0 de longitud.


Si está buscando una respuesta rápida, busqué "power set de Python" en google y se me ocurrió esto: Python Power Set Generator

Aquí hay un copiar y pegar del código en esa página:

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

Esto se puede usar así:

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

Ahora r es una lista de todos los elementos que deseaba, y se puede ordenar e imprimir:

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


Solo quería ofrecer la solución más comprensible, la versión anti código 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

Los resultados

Todos los conjuntos de longitud 0

[()]

Todos los conjuntos de longitud 1

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

Todos los conjuntos de longitud 2

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

Todos los conjuntos de longitud 3

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

Para obtener más información, consulte los documentos de itertools , también la entrada de wikipedia en los conjuntos de poder.


""" from https://docs.python.org/3.6/library/itertools.html uses the module itertools chaining together the two functions combinations() and chain() is faster than iterating and generator functions in Python Author: joltE Date: 3/15/2017 """ def powerset(iterable): "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" from itertools import chain, combinations s = list(iterable) return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) def AllCombo(items): return [list(i) for i in powerset(items)]

Banco de pruebas

print(AllCombo([1, 3, 5, 7])) print([list(i) for i in powerset([1, 3, 5, 7])])

powerset () actúa como una función de generador, pero es más eficiente debido al uso exclusivo de las funciones integradas de iterador de cadena () y combinaciones (). powerset () genera tuplas, esto se puede convertir en listas, como se hizo en AllCombo con la función list (). Ambas sentencias de impresión en el banco de pruebas emiten los mismos datos.


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

Por ejemplo:

get_power_set([1,2,3])

rendimiento

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


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