简体   繁体   中英

Reverse the order of key, value in an array conversion to a hash

Suppose I have an array of values, then keys (the reverse of what an assignment to a hash would expect):

use strict;
use warnings;
use Data::Dump;

my @arr = qw(1 one 2 two 3 three 4 four 1 uno 2 dos 3 tres 4 cuatro);

my %hash = @arr;

dd \%hash;

Prints

{ 1 => "uno", 2 => "dos", 3 => "tres", 4 => "cuatro" }

Obviously, the duplicate keys are eliminated when the hash is constructed.

How can I reverse the order of the pairs of values used to construct the hash?

I know that I can write a C style loop:

for(my $i=1; $i<=$#arr; $i=$i+2){
    $hash{$arr[$i]}=$arr[$i-1];
    }

dd \%hash;   
# { cuatro => 4, dos => 2, four => 4, one => 1, three => 3, tres => 3, two => 2, uno => 1 }

But that seems a little clumsy. I am looking for something a little more idiomatic Perl.

In Python, I would just do dict(zip(arr[1::2], arr[0::2]))

Use reverse :

my %hash = reverse @arr;

A list of the built-in functions in Perl is in perldoc perlfunc .

TLP has the right answer, but the other way to avoid eliminating dup keys is to use hash of arrays. I am assuming that's the reason for you reversing the array in the first place.

use strict;
use warnings;
use Data::Dump;

my @arr = qw(1 one 2 two 3 three 4 four 1 uno 2 dos 3 tres 4 cuatro);

my %hash;

push @{ $hash{$arr[$_]} }, $arr[$_ + 1] for grep { not $_ % 2 } 0 .. $#arr;

dd \%hash;

Output:

{
  1 => ["one", "uno"],
  2 => ["two", "dos"],
  3 => ["three", "tres"],
  4 => ["four", "cuatro"],
}

As suggested by ikegami in the comments, you can take a look at the List::Pairwise module available on CPAN for a more readable solution:

use strict;
use warnings;
use Data::Dump;
use List::Pairwise qw( mapp ); 

my @arr = qw(1 one 2 two 3 three 4 four 1 uno 2 dos 3 tres 4 cuatro);

my %hash;

mapp { push @{ $hash{$a} }, $b } @arr;

dd \%hash;

TLP has the right answer if your array of value, keys are ready to go into the hash.

That said, if you want to process the key or value in anyway before they go into the hash, I find this to be something I use:

while (my ($v, $k)=(shift @arr, shift @arr)) {
    last unless defined $k;
    # xform $k or $v in someway, like $k=~s/\s*$//; to strip trailing whitespace...
    $hash{$k}=$v;
}

(Note -- destructive to the array @arr . If you want to use @arr for something else, make a copy of it first.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM