Luke Luke - 1 month ago 8
Perl Question

perl put array element into hash

I have an array with a bunch of strings as elements, and I want to put then into hash. So I spilt the strings in the array first and then put the parsed strings into a new array call parse_list.

This is my code:

#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper qw(Dumper);
my %hash;

my $string_array = [
"Europe West France Spain Germany",
"Europe North Finland Iceland",
"Asia East Japan Korea China",
"America North Mexico USA Canada"
];

foreach my $country(@{$string_array}){
my @parse_list = split(/\s+/, $country);
(my $continent,my $region,) = @parse_list[0,1];
#I just know how to get the continent and region, I don't know how to put
#the element from index [2..4] to an array

}


How can I set

Continent as the primary key and the Region as the value in the first layer of the hash.

Region as the secondary key and the array Country as the value in the second layer of the hash.

so it is like

my %hash = (
Europe => {
West => [ "France", "Spain", "Germany"]
}
);

Answer Source

When you're "parsing" your list, it's not very helpful to store everything in a single array. Instead, put the data into more useful variables.

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my $string_array = [
  "Europe West France Spain Germany",
  "Europe North Finland Iceland",
  "Asia East Japan Korea China",
  "America North Mexico USA Canada"
];

my %geography;

for (@$string_array) {
  my ($continent, $region, @countries) = split;

  $geography{$continent}{$region} = \@countries;
}

print Dumper \%geography;

The output is:

$VAR1 = {
          'America' => {
                         'North' => [
                                      'Mexico',
                                      'USA',
                                      'Canada'
                                    ]
                       },
          'Europe' => {
                        'West' => [
                                    'France',
                                    'Spain',
                                    'Germany'
                                  ],
                        'North' => [
                                     'Finland',
                                     'Iceland'
                                   ]
                      },
          'Asia' => {
                      'East' => [
                                  'Japan',
                                  'Korea',
                                  'China'
                                ]
                    }
        };

Update (to add some more explanation):

I've changed the name of %hash to %geography - naming variables well is very important.

When using the for (...) construct, it's often useful to use Perl's default behaviour and store the list elements in $_. This is because $_ is often the default input variable for various operations. In this case, for example, I could have written:

for my $geo (@$string_array) {
  my ($continent, $region, @countries) = split /\s+/, $geo;
  ...
}

But the split function works on $_ by default. And, even better, its standard behaviour is to split on /\s+/, so we can omit all that too and end up with much cleaner code:

for (@$string_array) {
  my ($continent, $region, @countries) = split;
  ...
}