2010-05-25 19 views
20

Si tengo un hash en Perl que contiene correlaciones enteras completas y secuenciales (es decir, todas las claves de 0 a n están mapeadas a algo, no hay claves fuera de esto), ¿hay algún medio de convirtiendo esto a una matriz?Perl, convertir hash a matriz

Sé que podría iterar sobre los pares clave/valor y colocarlos en una nueva matriz, pero algo me dice que debe haber un medio integrado para hacerlo.

+4

** ¡ADVERTENCIA IMPORTANTE! ** ¿Por qué todos quieren ordenar las llaves? No es necesario y hace que el algoritmo sea mucho más lento. ¡La clasificación es lenta! La respuesta de ** runrig ** es la mejor aquí. Funcionará si el hash es escaso. Las matrices mantienen el orden, pero son estructuras de acceso aleatorio. No estamos trabajando con listas vinculadas, ¡personas! – daotoad

+0

Tienes razón: hay una manera de hacerlo integrado. Ver [respuesta de Ether] (http://stackoverflow.com/questions/2907270/perl-convert-hash-to-array/2907469#2907469). :) Esta pregunta es otra razón por la que existe una diferencia entre el contexto de la lista y las matrices.Junto con las divisiones, te permite hacer conversiones entre listas y hash sin ninguna magia especial o iteración, y el imho es una de las características más potentes de Perl. –

Respuesta

20

Si el origen de datos original es un hash:

# first find the max key value, if you don't already know it: 
use List::Util 'max'; 
my $maxkey = max keys %hash; 

# get all the values, in order 
my @array = @hash{0 .. $maxkey}; 

O si los datos originales fuente es un hashref:

my $maxkey = max keys %$hashref; 
my @array = @{$hashref}{0 .. $maxkey}; 

Esto es fácil de probar usando este ejemplo:

my %hash; 
@hash{0 .. 9} = ('a' .. 'j'); 

# insert code from above, and then print the result... 
use Data::Dumper; 
print Dumper(\%hash); 
print Dumper(\@array); 

$VAR1 = { 
      '6' => 'g', 
      '3' => 'd', 
      '7' => 'h', 
      '9' => 'j', 
      '2' => 'c', 
      '8' => 'i', 
      '1' => 'b', 
      '4' => 'e', 
      '0' => 'a', 
      '5' => 'f' 
     }; 
$VAR1 = [ 
      'a', 
      'b', 
      'c', 
      'd', 
      'e', 
      'f', 
      'g', 
      'h', 
      'i', 
      'j' 
     ]; 
+0

No '->' operador para el hashref? – Zaid

+0

@Zaid: no, así no es como usas slices en hashrefs. – Ether

+1

Tonta, está siendo lanzado como una matriz, por lo que el operador de flecha no es necesario. – Zaid

12

Bien, esto no está muy "integrado" pero funciona. También es IMHO preferible a cualquier solución que implique "ordenar", ya que es más rápido.

map { $array[$_] = $hash{$_} } keys %hash; # Or use foreach instead of map 

De lo contrario, menos eficiente:

my @array = map { $hash{$_} } sort { $a<=>$b } keys %hash; 
+6

o para evitar el mapa en contexto vacío: $ array [$ _] = $ hash {$ _} para claves% hash; – runrig

+3

Eso tendría que ser un 'tipo {$ a <=> $ b}'. Recuerde que 'sort' se establece por defecto en comparaciones de cadenas. – Zaid

2

Esto dejará teclas no definidos en %hashed_keys como undef:

# if we're being nitpicky about when and how much memory 
# is allocated for the array (for run-time optimization): 
my @keys_arr = (undef) x scalar %hashed_keys; 

@keys_arr[(keys %hashed_keys)] = 
    @hashed_keys{(keys %hashed_keys)}; 

Y, si usted está utilizando referencias:

@{$keys_arr}[(keys %{$hashed_keys})] = 
    @{$hashed_keys}{(keys %{$hashed_keys})}; 

O, lo que es más peligroso, ya que asume que lo que dijiste es cierto (puede que no siempre sea cierto & hellip; ¡Sólo digo!):

@keys_arr = @hashed_keys{(sort {$a <=> $b} keys %hashed_keys)}; 

Pero esto es algo así como el punto. Si, para empezar, tenían un índice entero, ¿por qué están ahora en un hash?

+0

Buen uso de rebanadas. También es un buen punto sobre la elección inicial de la estructura de datos. Es una lástima que haya sacado 'sort', el género es lento (vea mi despotrica arriba) y propenso a errores, y no es deseable. – daotoad

+0

@daotoad: la primera (y recomendada) solución no utiliza 'sort'. Pero, estoy completamente de acuerdo con 'sort'; genera hasta llamadas de función arbitrarias n-cuadrado por invocación [sugerencia: esto es terrible]. – amphetamachine

12

Puede extraer todos los valores de un hash con la función values:

my @vals = values %hash; 

Si los quieres en un orden determinado, entonces usted puede poner las teclas en el orden deseado y luego tomar un hash slice de que:

my @sorted_vals = @hash{sort { $a <=> $b } keys %hash}; 
0

Como dijo DVK, no hay construido en el camino, pero esto va a hacer el truco:

my @array = map {$hash{$_}} sort {$a <=> $b} keys %hash; 

o esto:

my @array; 

keys %hash; 

while (my ($k, $v) = each %hash) { 
    $array[$k] = $v 
} 

de referencia para ver que es más rápido, creo que ha de ser el segundo.

+0

Bueno, el primero va a ser O (NlogN) en promedio, pero hasta O (N^2). El segundo método es simplemente O (N). Sin necesidad de puntos de referencia – daotoad

4

Perl no proporciona un built-in para resolver su problema.

Si sabe que las claves cubren una determinada gama 0..N, puede aprovechar este hecho:

my $n = keys(%hash) - 1; 
my @keys_and_values = map { $_ => $hash{$_} } 0 .. $n; 
my @just_values  = @hash{0 .. $n}; 
+0

O 'my $ n = $ # {[keys% hash]}' si tiene una aversión a sustracción constante ... – Zaid

0

Combinando FM 's y Ether' respuestas s permite evitar la definición de un escalar otra manera innecesaria:

my @array = @hash{ 0 .. $#{[ keys %hash ]} }; 

Lo bueno es que a diferencia con el enfoque scalar, $# funciona arriba incluso en el caso improbable de que el índice predeterminado del primer elemento, $[, sea distinto de cero.

Por supuesto, eso significaría escribir algo tonto y ofuscado, así:

my @array = @hash{ $[ .. $#{[ keys %hash ]} }; # Not recommended 

Pero entonces siempre existe la remota posibilidad de que alguien necesita alguna parte (mueca de dolor ) ...

0
@a = @h{sort { $a <=> $b } keys %h}; 
1
$Hash_value = 
{ 
'54' => 'abc', 
'55' => 'def', 
'56' => 'test', 
}; 
while (my ($key,$value) = each %{$Hash_value}) 
{ 
print "\n $key > $value"; 
} 
0

podemos escribir un tiempo de la siguiente manera:

$j =0; 
while(($a1,$b1)=each(%hash1)){ 
    $arr[$j][0] = $a1; 
    ($arr[$j][1],$arr[$j][2],$arr[$j][3],$arr[$j][4],$arr[$j][5],$arr[$j][6]) = values($b1); 
    $j++; 
} 

$ a1 contiene la clave y $ b1 contiene los valores En el ejemplo anterior tengo Hash de matriz y la matriz contiene 6 elementos.

0

Una manera fácil es hacer @array = %hash

Por ejemplo,

my %hash = (
    "0" => "zero", 
    "1" => "one", 
    "2" => "two", 
    "3" => "three", 
    "4" => "four", 
    "5" => "five", 
    "6" => "six", 
    "7" => "seven", 
    "8" => "eight", 
    "9" => "nine", 
    "10" => "ten", 
); 

my @array = %hash; 

print "@array"; produciría la siguiente salida,

3 tres 9 nueve 5 cinco 8 ocho 2 dos 4 cuatro 1 uno 10 diez 7 siete 0 cero 6 seis