perl data-structures hash perl-data-structures

¿Cómo puedo mantener el orden de las claves que agrego a un hash Perl?



data-structures perl-data-structures (6)

¿Cómo puedo mantener el orden de la lista real después de contar su ocurrencia utilizando un hash en el siguiente programa? Por ejemplo, <DATA> son

a b e a c d a c d b etc.

Usando hash, conté la ocurrencia de cada elemento.

y lo que quiero es:

a 3 b 2 e 1 c 2 d 2

pero el siguiente programa me muestra lo contrario.

my (%count, $line, @array_1, @array_2); while ($line = <DATA>) { $count{$line}++ if ( $line =~ //S/ ); } @array_1 = keys(%count); @array_2 = values(%count); for(my $i=0; $i<$#array_1; $i++) { print "$array_1[$i]/t $array_2[$i]"; }



Los datos en una tabla hash se almacenan en orden del código hash de las teclas, que para la mayoría de los propósitos es como un orden aleatorio. También desea almacenar el orden de la primera aparición de cada tecla. Aquí hay una forma de abordar este problema:

my (%count, $line, @display_order); while ($line = <DATA>) { chomp $line; # strip the /n off the end of $line if ($line =~ //S/) { if ($count{$line}++ == 0) { # this is the first time we have seen the key "$line" push @display_order, $line; } } } # now @display_order holds the keys of %count, in the order of first appearance foreach my $key (@display_order) { print "$key/t $count{$key}/n"; }


Los hashes no están ordenados, pero como de costumbre, CPAN ofrece una solución: Tie :: IxHash

use Tie::IxHash; my %count; tie %count, ''Tie::IxHash''; while ($line = <DATA>) { $count{$line}++ if ( $line =~ //S/ ); } while( my( $key, $value)= each %count) { print "$key/t $value"; }


Simplemente:

my (%count, @order); while(<DATA>) { chomp; push @order, $_ unless $count{$_}++; } print "$_ $count{$_}/n" for @order; __DATA__ a b e a c d a c d b


No estoy convencido de que esta sea siempre una técnica mejor, pero a veces la he usado. En lugar de tener el tipo de hash "visto", puede almacenar tanto el recuento como el orden notado.

Básicamente, en lugar de $count{$line} teniendo el número de veces visto, $count{$line}{count} es el tiempo visto y $count{$line}{order} es el orden en que se vio.

my %count; while (my $line = <DATA>) { chomp $line; if ($line =~ //S/) { $count{$line} ||= { order => scalar(keys(%count)) }; $count{$line}{count}++; } } for my $line (sort { $count{$a}{order} <=> $count{$b}{order} } keys %count ) { print "$line $count{$line}{count}/n"; }


Otra opción es el módulo puro perl Hash::Ordered David Golden (@xdg). Obtienes orden pero es más lento ya que el hash se convierte en un objeto detrás de escena y usas métodos para acceder y modificar los elementos hash.

Probablemente haya puntos de referencia que puedan cuantificar cuánto más lento es el módulo que los hashes regulares, pero es una buena manera de trabajar con estructuras de datos clave / valor en pequeños guiones y lo suficientemente rápido para mí en ese tipo de aplicaciones. La documentación menciona varios otros enfoques para ordenar un hash también.