C'è un modo per ottenere un sub-hash? Devo usare una fetta di hash?Come posso ottenere una sola parte di un hash in Perl?
Ad esempio:
%hash = (a => 1, b => 2, c => 3);
voglio solo
%hash = (a => 1, b => 2);
C'è un modo per ottenere un sub-hash? Devo usare una fetta di hash?Come posso ottenere una sola parte di un hash in Perl?
Ad esempio:
%hash = (a => 1, b => 2, c => 3);
voglio solo
%hash = (a => 1, b => 2);
Hash slices restituiscono i valori associati a un elenco di chiavi. Per ottenere una fetta hash si cambia il sigillo a @ e fornire un elenco di chiavi (in questo caso "a"
e "b"
):
my @items = @hash{"a", "b"};
spesso è possibile utilizzare un operatore citazione parola per produrre l'elenco:
my @items = @hash{qw/a b/};
è inoltre possibile assegnare ad una fetta di hash, quindi se volete un nuovo hash che contiene un sottoinsieme di un altro hash si può dire
my %new_hash;
@new_hash{qw/a b/} = @hash{qw/a b/};
Molte persone utilizzano un map invece di fette di hash:
my %new_hash = map { $_ => $hash{$_} } qw/a b/;
A partire da Perl 5.20.0, è possibile ottenere le chiavi ed i valori in un solo passaggio se si utilizza il sigillo% invece del sigillo @:
my %new_hash = %hash{qw/a b/};
Un hash è un contenitore non ordinata, ma la fetta termine veramente solo ha senso in termini di un contenitore ordinato. Forse guarda usando un array. Altrimenti, potresti semplicemente rimuovere tutti gli elementi che non vuoi produrre il tuo 'sub-hash'.
In Perl, le fette di hash sono utili e completamente supportate. Per saperne di più rileggere [la sezione 'Slices' in _perldata_] (http://perldoc.perl.org/perldata.html#Slices). –
che vorreste probabilmente per assemblare un elenco di chiavi che si desidera:
my @keys = qw(a b);
e quindi utilizzare un ciclo per fare l'hash:
my %hash_slice;
for(@keys) {
$hash_slice{$_} = %hash{$_};
}
Oppure:
my %hash_slice = map { $_ => $hash{$_} } @keys;
(La mia preferenza è la seconda, ma quella che preferisci è la migliore.)
Troppa programmazione funzionale mi porta a pensare prima a zip
.
Con List::MoreUtils installato,
use List::MoreUtils qw(zip);
%hash = qw(a 1 b 2 c 3);
@keys = qw(a b);
@values = @hash{@keys};
%hash = zip @keys, @values;
Purtroppo, il prototipo di List :: di zip
moreutils inibisce
zip @keys, @hash{@keys};
Se davvero si vuole evitare la variabile intermedia, si potrebbe
zip @keys, @{[@hash{@keys}]};
Oppure scrivi il tuo zip
senza il prototipo problematico. (Questo non ha bisogno di List :: MoreUtils affatto.)
sub zip {
my $max = -1;
$max < $#$_and $max = $#$_ for @_;
map { my $ix = $_; map $_->[$ix], @_; } 0..$max;
}
%hash = zip \@keys, [@hash{@keys}];
Se avete intenzione di essere mutanti sul posto,
%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 in più che le soluzioni map
e zip
incorrono. (. Sì, mutando l'hash mentre state iterando su di esso è sicuro ... fino a quando la mutazione è l'eliminazione solo la coppia più recente iterata)
Spiega questo, per favore - '% keep = map + ($ _ => 1), qw (a b);'? –
FWIW, io uso Moose :: Autobox qui:
my $hash = { a => 1, b => 2, c => 3, d => 4 };
$hash->hslice([qw/a b/]) # { a => 1, b => 2 };
Nella vita reale, lo uso per estrarre "username" e "password" da un modulo di invio e passare a quello di Catalyst $c->authenticate
(che si aspetta, nel mio caso, un hashref contenente nome utente e password, ma nient'altro).
In che modo $ hash-> hslice (qw/a b /) è migliore di @ {$ hash} {qw/a b /}? O è uno di quei casi in cui, se devo chiedermi, sono troppo lontano per capire? –
Dovresti avere un modello di risposta in modo che "I use Moose ::" sia all'inizio di ogni risposta. :) –
Chas. Owens: non è quello che fa Hslice. @ {$ hash} {...} restituisce un elenco di valori; hslice restituisce un nuovo riferimento all'hash con entrambe le chiavi e i valori. – jrockway
Ancora un altro modo:
my @keys = qw(a b);
my %hash = (a => 1, b => 2, c => 3);
my %hash_copy;
@hash_copy{@keys} = @hash{@keys};
Nuovo in Perl 5.20 è fette di hash restituzione delle chiavi e valori utilizzando% come sull'ultima riga qui:
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!
Poiché non c'è nulla logicamente "slice" su Sospetto che qualcosa abbia a che fare con 'map'. In un array lo si farebbe basandosi su un indice, ma in un hash non esiste una rappresentazione interna affidabile dei dati in esso contenuti. Avresti bisogno di un qualche tipo di qualificatore (regex?) Per definire cosa dovrebbe andare nel subhash e cosa non dovrebbe. –
BTW, la sintassi dell'hash è sbagliata: usa le parentesi tonde "()" per un semplice hash, "{}" per i riferimenti hash anonimi. – trendels