2011-07-13 19 views
5

Tengo un hash de identificadores de cadena. ¿Cuál es la mejor manera de barajar los ID?¿Cómo mezclar los valores en un hash?

A modo de ejemplo, mi picadillo asigna los siguientes identificadores:

this => 0 
is => 1 
a => 2 
test => 3 

Ahora me gustaría que barajar al azar eso. Un resultado ejemplo sería:

this => 1 
is => 0 
a => 3 
test => 2 
+0

Siempre se puede crear un hash de hashes diferentes al azar y luego seleccionar uno de esos;) – hemlocker

Respuesta

7

podría utilizar el método shuffle en List::Util a ayudar:

use List::Util qw(shuffle); 

... 

my @values = shuffle(values %hash); 
map { $hash{$_} = shift(@values) } (keys %hash); 
+1

'map' en el contexto de vacío es una abominación. –

+0

¿Es solo un problema de estilo o tiene una objeción técnica? (solo curiosidad) – Mat

+1

Cuando 'map' devolvió la lista (incluso en contexto vacío) fue un problema real. En estos días es solo un problema de estilo. Algunos, como yo, consideran una abominación confiar en un efecto secundario de una función para trabajar. Especialmente cuando tenemos una construcción que es tan corta que no usa un efecto secundario: '$ hash {$ _} = shift @values ​​para las claves% hash;' –

4

Una rebanada de hash sería la forma más clara para mí:

#!/usr/bin/perl 

use strict; 
use warnings; 

use List::Util qw/shuffle/; 
use Data::Dumper; 

my %h = (
    this => 0, 
    is => 1, 
    a => 2, 
    test => 3, 
); 

@h{keys %h} = shuffle values %h; 

print Dumper \%h; 

Esto tiene el inconveniente de que los valores hash enormes ocuparían mucha memoria a medida que sacaras todas sus claves y valores. Un (a partir de un punto de vista de la memoria) la solución más eficiente sería:

#!/usr/bin/perl 

use strict; 
use warnings; 

use List::Util qw/shuffle/; 
use Data::Dumper; 

my %h = (
    this => 0, 
    is => 1, 
    a => 2, 
    test => 3, 
); 

{ #bareblock to cause @keys to be garbage collected 
    my @keys = shuffle keys %h; 

    while (my $k1 = each %h) { 
     my $k2 = shift @keys; 
     @h{$k1, $k2} = @h{$k2, $k1}; 
    } 
} 

print Dumper \%h; 

Este código tiene la ventaja de tener sólo para duplicar las teclas (en lugar de las claves y valores).

El siguiente código no aleatoria de los valores (excepto en Perl 5.8.1 donde el orden de las claves se garantiza que sea al azar), pero no mezclar el orden. Se tiene el beneficio de trabajar en su lugar sin demasiado uso de memoria adicional:

#!/usr/bin/perl 

use strict; 
use warnings; 

use List::Util qw/shuffle/; 
use Data::Dumper; 

my %h = (
    this => 0, 
    is => 1, 
    a => 2, 
    test => 3, 
); 

my $k1 = each %h; 
while (defined(my $k2 = each %h)) { 
    @h{$k1, $k2} = @h{$k2, $k1}; 
    last unless defined($k1 = each %h); 
} 

print Dumper \%h; 
Cuestiones relacionadas