Perl, convert hash to array

2020-05-31 05:08发布

问题:

If I have a hash in Perl that contains complete and sequential integer mappings (ie, all keys from from 0 to n are mapped to something, no keys outside of this), is there a means of converting this to an Array?

I know I could iterate over the key/value pairs and place them into a new array, but something tells me there should be a built-in means of doing this.

回答1:

If your original data source is a 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};

Or if your original data source is a hashref:

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

This is easy to test using this example:

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'
        ];


回答2:

You can extract all the values from a hash with the values function:

my @vals = values %hash;

If you want them in a particular order, then you can put the keys in the desired order and then take a hash slice from that:

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


回答3:

OK, this is not very "built in" but works. It's also IMHO preferrable to any solution involving "sort" as it's faster.

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

Otherwise, less efficient:

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


回答4:

Perl does not provide a built-in to solve your problem.

If you know that the keys cover a particular range 0..N, you can leverage that fact:

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


回答5:

This will leave keys not defined in %hashed_keys as 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)};

And, if you're using references:

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

Or, more dangerously, as it assumes what you said is true (it may not always be true … Just sayin'!):

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

But this is sort of beside the point. If they were integer-indexed to begin with, why are they in a hash now?



回答6:

$Hash_value = 
{
'54' => 'abc',
'55' => 'def',
'56' => 'test',
};
while (my ($key,$value) = each %{$Hash_value})
{
 print "\n $key > $value";
}


回答7:

As DVK said, there is no built in way, but this will do the trick:

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

or this:

my @array;

keys %hash;

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

benchmark to see which is faster, my guess would be the second.



回答8:

@a = @h{sort { $a <=> $b } keys %h};


回答9:

Combining FM's and Ether's answers allows one to avoid defining an otherwise unnecessary scalar:

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

The neat thing is that unlike with the scalar approach, $# works above even in the unlikely event that the default index of the first element, $[, is non-zero.

Of course, that would mean writing something silly and obfuscated like so:

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

But then there is always the remote chance that someone needs it somewhere (wince)...



回答10:

We can write a while as below:

$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 contains the key and $b1 contains the values In the above example i have Hash of array and the array contains 6 elements.



回答11:

An easy way is to do @array = %hash

For example,

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"; would produce the following output,

3 three 9 nine 5 five 8 eight 2 two 4 four 1 one 10 ten 7 seven 0 zero 6 six



标签: perl hash arrays