开发者

How do you map an array [key1,val1] to a hash { key1 => val1} in perl?

开发者 https://www.devze.com 2023-04-10 10:15 出处:网络
The problem is I have an array that has the key value pairs as elements in an array and I have to split them up somehow into key => value pairs in a hash.

The problem is I have an array that has the key value pairs as elements in an array and I have to split them up somehow into key => value pairs in a hash.

my first attempt at this works, but I think its pretty messy - I have to get every other element of the arrays, and then filter through to find the accepted keys to create a hash with

my $HASH;
my $ARRAY = [ key1, val1, key2, val2, __key3__, val3, __key4_开发者_高级运维_, val4 ];
   my @keys = map{ $ARRAY[ $_*2   ] } 0 .. int($#ARRAY/2);
   my @vals = map{ $ARRAY[ $_*2+1 ] } 0 .. int($#ARRAY/2);

   my $i = 0;
   #filter for keys that only have __key__ format
    for $key (@keys){
      if( $key && $key =~ m/^__(.*)__$/i ){
       $HASH{$1} = $vals[$i];
      }
     $i++;
    }
   # only key3 and key4 should be in $HASH now

I found this sample code which I think is close to what I'm looking for but I cant figure out how to implement something similar over an array rather than iterating over lines of a text file:

$file = 'myfile.txt'
open I, '<', $file
my %hash;
%hash = map { split /\s*,\s*,/,$_,2 } grep (!/^$/,<I>);
print STDERR "[ITEM] $_ => $hash{$_}\n" for keys %hash;

Can any of you perl gurus out there help me understand the best way to do this? Even if I could somehow join all the elements into a string then split over every second white space token -- that might work too, but for now Im stuck!


This is very easy:

use strict; use warnings;
use YAML;

my $ARRAY = [qw(key1 val1 key2 val2 __key3__ val3 __key4__ val4)];
my $HASH =  { @$ARRAY };

print Dump $HASH;

Output:

C:\Temp>
---
__key3__: val3
__key4__: val4
key1: val1
key2: val2


my $ARRAY = [ qw(key1 val1 key2 val2 key3 val3 key4 val4) ];
my $HASH = { @$ARRAY };


In the sample code you found, the <I> portion reads in the entire file and returns a list to grep. grep processes the list and then passes it to map. Map then creates its own list and this list is assigned to the hash.

When you assign a list to a hash, the list is assumed to be an even list of key/value pairs.

It does not matter where this list comes from, it could be the output of a map, grep, or split command. It could be right from a file, it could be stored in an array.

Your line:

my $HASH = ();

Does not do anything useful. Writing my $HASH; is exactly the same.

At this point, $HASH is undefined. When you have an undefined value and you dereference it as a hash, %$HASH, the undefined value will become a hash.

You can make this explicit by writing:

my $HASH = {};  # note the curly braces and not parens

If you have a list of key value pairs in an array:

%$HASH = @array;

If you have a list of keys and a list of values:

@$HASH{@keys} = @values;

Per your question, here is one simple way of creating your hash from the array while filtering the values:

my $HASH = {};
my $ARRAY = [ qw(key1 val1 key2 val2 __key3__ val3 __key4__ val4) ];

{my @list = @$ARRAY;  # make a copy since splice eats the list
    while (my ($k, $v) = splice @list, 0, 2) {
        if ($k =~ /^__(.+)__$/) {
            $$HASH{$1} = $v
        }
    }
}

use Data::Dumper;

print Dumper($HASH);

which prints:

$VAR1 = {
          'key4' => 'val4',
          'key3' => 'val3'
        };

If you want to do that all in one line, you could use the function mapn from my module List::Gen which is a function like map but that allows you to move over the list with any step size you want, not just one item at a time.

use List::Gen 'mapn';

%$HASH = mapn {/^__(.+)__$/ ? ($1, $_[1]) : ()} 2 => @$ARRAY;


I didnt know you could dump the array and hash would figure it out.

There's nothing magical about values that come from an array. There's nothing for the hash to figure out.

If you assign a list to a hash, it will clear the hash, then treat the list as a list of key-value pairs from which to initialise the hash. So

%hash = ( foo => 1, bar => 2 );

is equivalent to

my @anon = ( foo => 1, bar => 2 );
%hash = ();
while (@anon) {
   my $key = shift(@anon);
   my $val = shift(@anon);
   $hash{$key} = $val;
}

A list is a list. It doesn't matter if it was produced using the list/comma op

x => "foo", y => "bar"

using qw()

qw( x foo y bar )

or using an array

@array

So that means the following are all the same.

%hash = ( x => "foo", y => "bar" );
%hash = qw( x foo y bar );
%hash = @array;  # Assuming @array contains the correct values.

And so are

$hash = { x => "foo", y => "bar" };
$hash = {qw( x foo y bar )};
$hash = { @array };  # Assuming @array contains the correct values.


Since your particular case has already been answered, I thought I would answer the case of what I took your question to ask. I expected to see an array of pairs like [ key => $value ], and that you wanted to put into either an array of hashes or a hash:

That answer goes like so:

my %hash = map { @$_ } [[ key1 => $value1 ], [ key2 => $value2 ], ... ];
my @ha   = map {; { @$_ } } [[ key1 => $value1 ], [ key2 => $value2 ], ... ];

my %hash = @$array_ref_of_values;

Only, I take each one and "explode" them, through dereferencing ( @$_ ).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号