2009-06-11 21 views
17

¿Hay alguna manera de obtener un sub-hash? ¿Necesito usar una porción hash?¿Cómo puedo obtener una parte única de hash en Perl?

Por ejemplo:

%hash = (a => 1, b => 2, c => 3); 

sólo quiero

%hash = (a => 1, b => 2); 
+0

Como no hay nada lógicamente a "slice" en Sospecho que algo tiene que ver con 'map'. En un conjunto, lo haría en función de un índice, pero en un hash no hay una representación interna confiable de los datos en él. ¿Necesitaría algún tipo de calificador (regex?) Para definir qué debería ir en el subhaz y qué no. –

+3

Por cierto, su sintaxis hash es incorrecta: use las llaves redondas "()" para un hash simple, "{}" para las referencias hash anónimas. – trendels

Respuesta

46

Hash slices devuelve los valores asociados con una lista de claves. Para obtener una tajada de hash se cambia el sello a @ y proporcionar una lista de claves (en este caso "a" y "b"):

my @items = @hash{"a", "b"}; 

A menudo se puede utilizar un operador de palabra cita para producir la lista:

my @items = @hash{qw/a b/}; 

también puede asignar a una rebanada de hash, así que si quieres un nuevo hash que contiene un subconjunto de otro hash que se puede decir

my %new_hash; 
@new_hash{qw/a b/} = @hash{qw/a b/}; 

Mucha gente va a utilizar un map en lugar de rodajas de patata:

my %new_hash = map { $_ => $hash{$_} } qw/a b/; 

A partir de Perl 5.20.0, usted puede obtener las claves y los valores en un solo paso si utiliza el sigilo% en lugar del @ sigilo:

my %new_hash = %hash{qw/a b/}; 
+0

esto hace que el "mapa" funcione con hashe un poco más claro para mí. Gracias –

+0

Larry Wall, brian d foy, y ... Chas. Owens ... ¡gracias por esta explicación tan completa! – bernie

+4

Probablemente debas aclarar que una rebanada hash solo tiene los valores, no los pares clave/valor. – ysth

-3

Un hash es un contenedor desordenada, pero el término segmento en realidad sólo tiene sentido en términos de un contenedor de pedido. Tal vez investigar el uso de una matriz. De lo contrario, puede que tenga que eliminar todos los elementos que no desea producir su 'sub-hash'.

+0

En Perl, las rebanadas hash son útiles y totalmente compatibles. Para obtener más información vuelva a leer [la sección 'Rebanadas' en _perldata_] (http://perldoc.perl.org/perldata.html#Slices). –

9

Usted probablemente querrá para armar una lista de claves que desee:

my @keys = qw(a b); 

Y a continuación, utilizar un bucle para hacer el hash:

my %hash_slice; 
for(@keys) { 
    $hash_slice{$_} = %hash{$_}; 
} 

O:

my %hash_slice = map { $_ => $hash{$_} } @keys; 

(Mi preferencia es la segunda, pero la que más te guste)

3

Demasiada programación funcional me lleva a pensar primero en zip.

Con List::MoreUtils instalado,

use List::MoreUtils qw(zip); 

%hash = qw(a 1 b 2 c 3); 
@keys = qw(a b); 
@values = @hash{@keys}; 
%hash = zip @keys, @values; 

Por desgracia, el prototipo de la Lista :: de zip MoreUtils inhibe

zip @keys, @hash{@keys}; 

Si realmente quiere evitar la variable intermedia, podría

zip @keys, @{[@hash{@keys}]}; 

O simplemente escriba su propia zip sin el prototipo problemático. (Esto no necesita List :: MoreUtils en absoluto.)

sub zip { 
    my $max = -1; 
    $max < $#$_and $max = $#$_ for @_; 
    map { my $ix = $_; map $_->[$ix], @_; } 0..$max; 
} 

%hash = zip \@keys, [@hash{@keys}]; 

Si usted va a ser la mutación en el lugar,

%hash = qw(a 1 b 2 c 3); 
%keep = map +($_ => 1), qw(a b); 
$keep{$a} or delete $hash{$a} while ($a, $b) = each %hash; 

evita la copia extra que los map y zip soluciones incurren. (Sí., Mutando el hash mientras se está interactuando sobre que es seguro ... siempre y cuando la mutación sólo se está eliminando el par más recientemente iterada)

+0

Explique esto, por favor - '% keep = map + ($ _ => 1), qw (a b);'? –

3

Fwiw, utilizo Moose :: Autobox aquí:

my $hash = { a => 1, b => 2, c => 3, d => 4 }; 
$hash->hslice([qw/a b/]) # { a => 1, b => 2 }; 

En la vida real, utilizo esto para extraer "nombre de usuario" y "contraseña" de un envío de formulario, y pasarlo a Catalyst's $c->authenticate (que espera, en mi caso, un hashref que contenga el nombre de usuario y contraseña, pero nada más)

+1

¿Cómo es mejor que $ hash-> hslice (qw/a b /) que @ {$ hash} {qw/a b /}? ¿O es este uno de esos casos en los que, si tengo que preguntar, estoy demasiado lejos para comprender? –

+4

Debe tener una plantilla de respuesta para que "Yo use Moose ::" esté al inicio de cada respuesta. :) –

+1

Chas. Owens: eso no es lo que hslice hace. @ {$ hash} {...} devuelve una lista de valores; hslice devuelve una nueva referencia hash con claves y valores. – jrockway

6

embargo, otra forma:

my @keys = qw(a b); 
my %hash = (a => 1, b => 2, c => 3); 
my %hash_copy; 
@hash_copy{@keys} = @hash{@keys}; 
2

nuevo en Perl 5.20 es rodajas de patata que vuelven claves, así como los valores mediante el uso de% como en la última línea aquí:

my %population = ('Norway',5000000,'Sweden',9600000,'Denmark',5500000); 
my @slice_values = @population{'Norway','Sweden'}; # all perls can do this 
my %slice_hash = %population{'Norway','Sweden'}; # perl >= 5.20 can do this! 
Cuestiones relacionadas