Dado un conjunto
{0, 1, 2, 3}
¿Cómo puedo producir los subconjuntos?
[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}]
Respuestas:
La itertools
página de Python tiene exactamente una powerset
receta para esto:
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))
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 cambiar la range
declaración a range(1, len(s)+1)
para evitar una combinación de longitud 0.
s = list(iterable)
necesita?
__len__
implementado; Pruébelo powerset((n for n in range(3)))
sin envolver la lista.
powerset(range(3))
funcionaría bien incluso sins = list(iterable)
.
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, encendido". Puedes cambiar la declaración de rango a rango (1, len (s) +1) para evitar una combinación de longitud 0 ", excepto que en mi caso cambia for i in range(1 << x)
a for i in range(1, 1 << x)
.
Volviendo a esto años más tarde, 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í, di:
print(list(powerset([4, 5, 6])))
Usar yield
significa que no es necesario calcular todos los resultados en una sola pieza de memoria. Se supone que el cálculo previo de las máscaras fuera del bucle principal es una optimización útil.
Si está buscando una respuesta rápida, acabo de buscar "Python Power Set" en Google y se me ocurrió esto: Python Power Set Generator
Aquí hay una copia y pegado 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]]
[[][]]
, para solucionarlo, solo separe los casos para la verificación de longitudif len(seq) == 0: yield [] elif len(seq) == 1: yield seq yield []
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
Sé que he agregado una respuesta anteriormente, pero realmente me gusta mi nueva implementación. Estoy tomando un conjunto como entrada, pero en realidad podría ser cualquier iterable, y estoy devolviendo un conjunto de conjuntos que es el conjunto de potencia de la entrada. Me gusta este enfoque porque está más alineado con la definición matemática de conjunto de potencia ( conjunto de todos los subconjuntos ).
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
Si desea exactamente el resultado que publicó en su respuesta, use esto:
>>> [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}]
Se sabe que el número de elementos del conjunto de potencia es 2 ** len(A)
, por lo que se puede ver claramente en el for
bucle.
Necesito convertir la entrada (idealmente un conjunto) en una lista porque por conjunto hay una estructura de datos de elementos únicos desordenados, y el orden será crucial para generar los subconjuntos.
selector
es clave en este algoritmo. Tenga en cuenta que selector
tiene la misma longitud que el conjunto de entrada, y para que esto sea posible, está usando una cadena f con relleno. Básicamente, esto me permite seleccionar los elementos que se agregarán a cada subconjunto durante cada iteración. Digamos que el conjunto de entrada tiene 3 elementos{0, 1, 2}
, por lo que el selector tomará valores entre 0 y 7 (inclusive), que en binario son:
000 # 0
001 # 1
010 # 2
011 # 3
100 # 4
101 # 5
110 # 6
111 # 7
Por lo tanto, cada bit podría servir como indicador si se debe agregar o no un elemento del conjunto original. Mire los números binarios y piense en cada número como un elemento del superconjunto, lo que 1
significa que un elemento en el índicej
debe agregar y 0
que este elemento no se debe agregar.
Estoy usando una comprensión de conjunto para generar un subconjunto en cada iteración, y convierto este subconjunto en un frozenset
para poder agregarlo aps
(conjunto de potencia). De lo contrario, no podré agregarlo porque un conjunto en Python consiste solo en objetos inmutables.
Puede simplificar el código usando algunas comprensiones de Python, para que pueda deshacerse de esos bucles for. También puede usar zip
para evitar el uso de j
index y el código terminará como el siguiente:
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)
}
Eso es. Lo que me gusta de este algoritmo es que es más claro e intuitivo que otros porque parece bastante mágico para confiar en itertools
él, aunque funciona como se esperaba.
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]]
power_set
) en el ciclo que gobierna es una práctica muy cuestionable. Por ejemplo, supongamos que usted escribió esto en vez de al código variable modificadora propuesta: power_set += [list(sub_set)+[elem]]
. Entonces el bucle no termina.
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_powerset(remaining_list):
subsets.append(partial_subset)
subsets.append(partial_subset[:] + [first_element])
return subsets
Otra forma de generar el conjunto de potencias es generando todos los números binarios que tienen n
bits. Como conjunto de potencia, 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 la ciencia de datos, y considero que es uno de los algoritmos más fáciles de entender que he visto.
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 sobre conjuntos de potencia
¡Solo un repaso rápido del conjunto de energía!
El conjunto de potencia de un conjunto X, es simplemente el conjunto de todos los subconjuntos de X, incluido el conjunto vacío
Conjunto de ejemplo X = (a, b, c)
Conjunto de poder = {{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}, {c}, {}}
Aquí hay otra forma de encontrar el conjunto de potencia:
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]))
crédito completo a la fuente
Esto se puede hacer de forma muy natural con 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}
Una forma sencilla sería aprovechar la representación interna de números enteros bajo aritmética de complemento a 2.
La representación binaria de números enteros es {000, 001, 010, 011, 100, 101, 110, 111} para números que van del 0 al 7. Para un valor de contador de números enteros, se considera 1 como inclusión del elemento correspondiente en la colección y '0' como exclusión podemos generar subconjuntos basados en la secuencia de conteo. Los números tienen que ser generado a partir 0
de pow(2,n) -1
la que N es la longitud de la matriz es decir, número de bits en la representación binaria.
Una función de generador de subconjuntos simple basada en ella se puede escribir como se muestra a continuación. Básicamente se basa
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
y luego se puede usar como
def get_subsets(array):
powerset = []
for i in subsets(array):
powerser.append(i)
return powerset
Pruebas
Añadiendo lo siguiente en el archivo local
if __name__ == '__main__':
sample = ['b', 'd', 'f']
for i in range(len(sample)):
print "Subsets for " , sample[i:], " are ", get_subsets(sample[i:])
da la siguiente salida
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']]
Con un conjunto vacío, que es parte de todos los subconjuntos, puede usar:
def subsets(iterable):
for n in range(len(iterable) + 1):
yield from combinations(iterable, n)
Casi todas estas respuestas usan en list
lugar de set
, lo que me pareció un poco engañoso. Entonces, por curiosidad, intenté hacer una versión simple realmente enset
y resumida para otras personas "nuevas en Python".
Descubrí que hay un par de rarezas al tratar con la implementación de conjuntos de Python . La principal sorpresa para mí fue manejar sets vacíos. Esto contrasta con la implementación de Ruby's Set , donde simplemente puedo hacer Set[Set[]]
y obtener Set
uno que contenga uno vacío Set
, por lo que inicialmente lo encontré un poco confuso.
Para revisar, al hacer powerset
con set
s, encontré dos problemas:
set()
toma un iterable, por set(set())
lo que volverá set()
porque el conjunto vacío iterable está vacío (duh, supongo :))set({set()})
y set.add(set)
no funcionará porque set()
no se puede mezclarPara resolver ambos problemas, utilicé frozenset()
utilicé , lo que significa que no obtengo lo que quiero (el tipo es literalmente set
), pero hace uso de la set
interacción general .
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 continuación, obtenemos 2² (16) frozenset
s correctamente como salida:
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})}
Como no hay forma de tener una set
de set
s en Python, si desea convertir estas frozenset
s en set
s, tendrá que volver a mapearlas en a list
( list(map(set, powerset(set([1,2,3,4]))))
) o modificar lo anterior.
Quizás la pregunta esté envejeciendo, pero espero que mi código ayude a alguien.
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
Utilice la función powerset()
del paquete more_itertools
.
Produce todos los subconjuntos posibles del iterable
>>> list(powerset([1, 2, 3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
Si quieres conjuntos, usa:
list(map(set, powerset(iterable)))
Obteniendo todos los subconjuntos con recursividad. Una sola línea de culo loco
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 [[]]
Basado en una solución de Haskell
subsets :: [a] -> [[a]]
subsets [] = [[]]
subsets (x:xs) = map (x:) (subsets xs) ++ subsets xs
NameError: name 'List' is not defined
List
importación
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
Puedes hacerlo así:
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]))
Salida:
[[], [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]]
Sé que es demasiado tarde
Ya hay muchas otras soluciones, pero aún así ...
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
Esto es una locura 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 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([]) ])
Sin embargo, me encantaría ver una mejor implementación.
[*map(set, chain.from_iterable(combinations(s, r) for r in range(len(s)+1)))]
; la función arg de map
puede ser frozenset
si lo prefiere.
Aquí está mi implementación rápida utilizando combinaciones pero usando solo incorporados.
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
Todos los subconjuntos en el rango n según lo establecido:
n = int(input())
l = [i for i in range (1, n + 1)]
for number in range(2 ** n) :
binary = bin(number)[: 1 : -1]
subset = [l[i] for i in range(len(binary)) if binary[i] == "1"]
print(set(sorted(subset)) if number > 0 else "{}")
import math
def printPowerSet(set,set_size):
pow_set_size =int(math.pow(2, set_size))
for counter in range(pow_set_size):
for j in range(set_size):
if((counter & (1 << j)) > 0):
print(set[j], end = "")
print("")
set = ['a', 'b', 'c']
printPowerSet(set,3)
Una variación de la pregunta es un ejercicio que veo en el libro "Descubriendo la informática: problemas interdisciplinarios, principios y programación en Python. Edición de 2015". En ese ejercicio 10.2.11, la entrada es solo un número entero y la salida deben ser los conjuntos de potencias. Aquí está mi solución recursiva (sin usar nada más que python3 básico)
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))
Y la salida es
[[], [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]] Número de sublistas: 16
No me había encontrado con la more_itertools.powerset
función y recomendaría usarla. También recomiendo no usar el orden predeterminado de la salida de itertools.combinations
, a menudo, en cambio, desea minimizar la distancia entre las posiciones y ordenar los subconjuntos de elementos con una distancia más corta entre ellos arriba / antes de los elementos con una mayor distancia entre ellos.
La itertools
página de recetas muestra que usachain.from_iterable
r
aquí coincide con la notación estándar para la parte inferior de un coeficiente binomial , s
generalmente se hace referencia a él n
en los textos de matemáticas y en las calculadoras ("n Elija 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))
Los otros ejemplos aquí dan el conjunto de potencias de [1,2,3,4]
de tal manera que las 2 tuplas se enumeran en orden "lexicográfico" (cuando imprimimos los números como enteros). Si escribo la distancia entre los números a su lado (es decir, la diferencia), muestra mi punto:
12 ⇒ 1
13 ⇒ 2
14 ⇒ 3
23 ⇒ 1
24 ⇒ 2
34 ⇒ 1
El orden correcto para los subconjuntos debe ser el orden que 'agota' la distancia mínima primero, así:
12 ⇒ 1
23 ⇒ 1
34 ⇒ 1
13 ⇒ 2
24 ⇒ 2
14 ⇒ 3
El uso de números aquí hace que este orden parezca "incorrecto", pero considere, por ejemplo, las letras ["a","b","c","d"]
, es más claro por qué esto podría ser útil para obtener el conjunto de potencias en este orden:
ab ⇒ 1
bc ⇒ 1
cd ⇒ 1
ac ⇒ 2
bd ⇒ 2
ad ⇒ 3
Este efecto es más pronunciado con más elementos, y para mis propósitos marca la diferencia entre poder describir los rangos de los índices del conjunto de potencias de manera significativa.
(Hay mucho escrito en códigos Gray etc. para el orden de salida de los algoritmos en combinatoria, no lo veo como un problema secundario).
De hecho, acabo de escribir un programa bastante complicado que usó este código de partición de entero rápido para generar los valores en el orden correcto, pero luego descubrí more_itertools.powerset
y para la mayoría de los usos probablemente esté bien usar esa función así:
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)
Escribí algo de código más complicado que imprimirá el powerset muy bien (ver el repositorio de impresión bastante funciones que no he incluido aquí: print_partitions
, print_partitions_by_length
, y pprint_tuple
).
pset_partitions.py
Todo esto es bastante simple, pero aún puede ser útil si desea algún código que le permita acceder directamente a los diferentes niveles del conjunto de potencia:
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
Como ejemplo, escribí un programa de demostración CLI que toma una cadena como argumento de línea de comando:
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
Si desea una longitud específica de subconjuntos, puede hacerlo así:
from itertools import combinations
someSet = {0, 1, 2, 3}
([x for i in range(len(someSet)+1) for x in combinations(someSet,i)])
De manera más general, para los subconjuntos de longitud arbitraria, puede modificar el rango de rango. La salida es
[(), (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 )]
def powerset(some_set):
res = [(a,b) for a in some_set for b in some_set]
return res