Saash Tech
Saash Tech

Reputation: 35

Perl array numbers to hash

In Perl, I have an array

my @array = (1 3 6 12);

From the above array, I want hash which is mapped from one to next value and continue.

I want this to be output like this. And the last the number should be mapped to its own

$VAR1 = {,
          '1'  => '3',
          '3'  => '6',
          '6'  => '12',
          '12' => '12'
        };

This is the code I have tried to get the hash from arrays in Perl

use strict;
use warnings;
use Data::Dumper qw(Dumper);

my @array = qw(1 3 6 12);

my %hash = @array;

print Dumper \%hash;

I get the output as:

$VAR1 = {
          '6' => '12',
          '1' => '3'
        };

Can someone help since I am beginner in Perl ?

Thanks in advance

Upvotes: 0

Views: 182

Answers (3)

OldManSeph
OldManSeph

Reputation: 2719

Step through the array and use each element as a key and the next element as the value unless you are at the last element:

 foreach $x(0..$#array) {
    ($x == $#array) ? ($hash{$array[$x]} = $array[$x]) : ($hash{$array[$x]} = $array[$x+1]);
 }
 foreach $y (sort {$a<=>$b} keys %hash) {
     print "$y => $hash{$y}\n";
 }

Upvotes: 0

Dave Cross
Dave Cross

Reputation: 69264

The common way to walk an array is to use a for loop to iterate over the elements of the array.

for (@values) {
  say $_;
}

But in this case, we need each element in the array as well as the next element in the array. So it'll be more convenient to iterate over the indexes of the array. We use the special variable $#values which gives us the final index in the array.

for (0 .. $#values) {
  say "The value at index $_ is $values[$_]"
}

We can then get next element as well:

for (0 .. $#values) {
  say "$values[$_] => $values[$_ + 1]"
}

Running that gets us close to the data we want:

1 => 3
3 => 6
6 => 12
Use of uninitialized value in concatenation (.) or string at array2hash line 10.
12 =>

But because 12 is the last element in the array, getting the next element makes no sense (and Perl gives us and undef value - hence the warning).

In your example, it looks like you want the final element to point to itself. We can use the "defined-or" operator (//) to handle that:

for (0 .. $#values) {
  say "$values[$_] => ", $values[$_ + 1] // $values[$_];
}

All that remains now is to store the required data in a hash:

my %values_hash;
for (0 .. $#values) {
  $values_hash{$values[$_]} =  $values[$_ + 1] // $values[$_];
}

Using Data::Dumper to examine our hash, we get this:

$VAR1 = {
          '3' => 6,
          '12' => 12,
          '6' => 12,
          '1' => 3
        };

Which (taking account of the fact that hashes are unordered) is what we wanted.

A Perl expert might rewrite it as:

my %values_hash = map {
  $values[$_] => $values[$_ + 1] // $values[$_]
} 0 .. $#values;

Update: Another approach would be to use a hash slice.

my %values_hash;
@values_hash{@values} = @values[1 .. $#values, $#values];

Upvotes: 5

choroba
choroba

Reputation: 241868

You can assign the array directly to the hash to get half of the pairs. Use an array slice to get the other half.

my %hash = (@values, @values[1 .. $#values, $#values]);

This doesn't work for an array with an odd number of elements, but it's unclear what output you expect in such a case. Also, it's unclear what to do with repeated elements.

Upvotes: 2

Related Questions