2009-06-15 10 views

Respuesta

12

Puede utilizar Data::PowerSet como Mateo menciona. Sin embargo, si, como se indica en su ejemplo, solo desea los subconjuntos adecuados y no cada subconjunto, debe hacer un poco más de trabajo.

# result: all subsets, except {68, 22, 43}. 
    my $values = Data::PowerSet->new({max => 2}, 68, 22, 43); 

Del mismo modo, si desea omitir el conjunto nulo, sólo tiene que añadir el min parámetro:

# result: all subsets, except {} and {68, 22, 43}. 
    my $values = Data::PowerSet->new({min => 1, max => 2}, 68, 22, 43); 

De lo contrario, para obtener todos los subconjuntos, basta con omitir ambos parámetros:

# result: every subset. 
    my $values = Data::PowerSet->new(68, 22, 43); 
+0

Según el ejemplo, supongo que quiere subconjuntos apropiados. – ysth

3

Como dice "conjunto matemático", supongo que quiere decir que no hay duplicados.

Una implementación ingenua que funciona para hasta 32 elementos:

my $set = [1,2,3]; 
my @subsets; 
for my $count (1..(1<<@$set)-2) { 
    push @subsets, [ map $count & (1<<$_) ? $set->[$_] :(), 0..$#$set ]; 
} 

(Para la gama completa de subconjuntos, bucle de 0 a (1 < < @ $ set) -1; excluyendo 0 excluye la hipótesis nula set, excluyendo (1 < < @ $ set) -1 excluye el conjunto original.)

Actualización: No estoy defendiendo esto sobre el uso de un módulo, solo lo sugiero en caso de que esté buscando entender cómo hacerlo Qué problema. En general, cada elemento está incluido o excluido de cualquier subconjunto dado. Desea elegir un elemento y generar primero todos los subconjuntos posibles de los otros elementos sin incluir su elemento elegido y luego todos los subconjuntos posibles de los otros elementos, incluido su elemento elegido. Aplique recursivamente esto a "generar todos los subconjuntos posibles". Finalmente, descarte el subconjunto nulo y el subconjunto no apropiado. En el código anterior, a cada elemento se le asigna un bit. En primer lugar, todos los subconjuntos se generan con el bit alto activado y luego con todos los que están apagados. Para cada una de esas alternativas, los subconjuntos se generan primero con el bit más próximo al más alto desactivado y luego activo. Continuando con esto hasta que estés trabajando en la parte más baja, con lo que terminas es con todos los números posibles, en orden.

+0

No sé cuánto importa, pero generalmente prefiero usar 1 << x en vez de 2 ** x, cuando se sabe que x es un número entero. –

+0

¿Desea profundizar en el funcionamiento del ciclo o, más específicamente, en la función de mapa? – aks

+0

@muteW: map hace $ _ loop sobre los índices de @ $ set (0 a 2 en el ejemplo), ve si el $ _ 'bit de $ count está configurado y si es así incluye el elemento $ _' th de @ $ establecido en la lista resultante. – ysth

1

Si no desea utilizar un módulo existente o no puede, simplemente puede codificar su propio algoritmo de generación de subconjuntos utilizando un bit-mask and a binary counter. El código de ejemplo siguiente -

#!/usr/bin/perl 
use strict; 
use warnings; 

my @set  = (1, 2, 3); 
my @bitMask = (0, 0, 0); #Same size as @set, initially filled with zeroes 

printSubset(\@bitMask, \@set) while (genMask(\@bitMask, \@set)); 

sub printSubset { 
    my ($bitMask, $set) = @_; 

    for (0 .. @$bitMask-1) { 
    print "$set->[$_]" if $bitMask->[$_] == 1; 
    } 
    print"\n"; 

} 

sub genMask { 
    my ($bitMask, $set) = @_; 

    my $i; 
    for ($i = 0; $i < @$set && $bitMask->[$i]; $i++) { 
    $bitMask->[$i] = 0; 
    } 

    if ($i < @$set) { 
    $bitMask->[$i] = 1; 
    return 1; 
    } 

    return 0; 
} 

Nota: No he podido probar el código, algunos errores pueden necesitar ser subsanadas.

1

Es un problema de conteo - para N elementos hay exactamente 2^N subconjuntos y tiene que contar de 0 a 2^N - 1 en binario para listarlos todos.

Por ejemplo, 3 elementos hay 8 posibles subconjuntos: 000, 001, 010, 011, 100, 101, 110 y 111 - los números muestran qué miembros están presentes.

Cuestiones relacionadas