0

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

2
  • 1
    What have you tried? What problems are you having? Commented Jun 4, 2021 at 9:39
  • 1
    Easy enough to do with a for loop. And $values_hash = ( ... );? That's not how you create a hash variable... Commented Jun 4, 2021 at 9:54

3 Answers 3

5

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];
Sign up to request clarification or add additional context in comments.

5 Comments

This solution doesn't help the OP print the hash in desired output
@steveo314: I don't understand your comment. The OP's question used Data::Dumper and I've shown the Data::Dumper output from my first example. What was the desired output that I haven't covered?
They wanted the output to be sorted by key in numerical order
@steveo314: Well, they don't specifically ask for that. It's true, the output in their question is sorted. But it's also true that the output is clearly from Data::Dumper. And given that hashes are inherently unsorted, that's hard to do. You can use $Data::Dumper::Sortkeys of course, but that does a string sort (so 12 sorts before 3).
When they give the desired output a certain way it usually means they desire the output that way. Data::Dumper doesn't sort the output unless you ask it to you like you mentioned.
2

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.

Comments

0

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";
 }

1 Comment

That maps each element to itself - which isn't what the question asked for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.