Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use perl references correctly

Tags:

reference

perl

I have a very noob-ish question here regarding refs, though still confounding to me at the very least...
In the code example below, i'm trying to create a hash of arrays:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper;

$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Quotekeys = 0;

my @a1 = ( 'a1', 1, 1, 1 );
my @a2 = ( 'a2', 2, 2, 2 );

my $a1_ref = \@a1;
my $a2_ref = \@a2;

my @a = ( $a1_ref, $a2_ref );

my %h = ();

for my $i ( 1 .. 2 ) {
        $h{"$i"} = \@a;
}

say Dumper \%h;

The Dumper output is

{
          '1' => [
                   [
                     'a1',
                     1,
                     1,
                     1
                   ],
                   [
                     'a2',
                     2,
                     2,
                     2
                   ]
                 ],
          '2' => $VAR1->{'1'}
        }

The question here is:
why is $h{'2'} a reference to $h{'1'}? I'm trying to create a hash %h with identical key-values made of the @a array-of-arrays. I want each key-value of the hash to have it's own AoA based on @a, but i'm getting references to $h{'1'} instead. What am i doing wrong??
The Dumper output i'm trying to achive is:

{
          '1' => [
                   [   
                     'a1',
                     1,  
                     1,  
                     1   
                   ],  
                   [   
                     'a2',
                     2,  
                     2,  
                     2   
                   ]   
                 ],  
          '2' => [
                   [   
                     'a1',
                     1,  
                     1,  
                     1   
                   ],  
                   [   
                     'a2',
                     2,  
                     2,  
                     2   
                   ]   
                 ]   
        }   

Any help appreciated. thanks in advance!
-dan

like image 925
Gnowl Avatar asked May 04 '13 19:05

Gnowl


People also ask

What is the use of reference in Perl?

A Perl reference is a scalar data type that holds the location of another value which could be scalar, arrays, or hashes. Because of its scalar nature, a reference can be used anywhere, a scalar can be used. You can construct lists containing references to other lists, which can contain references to hashes, and so on.

How do you reference an array in Perl?

Creating a reference to a Perl array If we have an array called @names, we can create a reference to the array using a back-slash \ in-front of the variable: my $names_ref = \@names;. We use the _ref extension so it will stand out for us that we expect to have a reference in that scalar.

How do I create a hash reference in Perl?

Similar to the array, Perl hash can also be referenced by placing the '\' character in front of the hash. The general form of referencing a hash is shown below. %author = ( 'name' => "Harsha", 'designation' => "Manager" ); $hash_ref = \%author; This can be de-referenced to access the values as shown below.


1 Answers

It's not that $h{'2'} is a reference to $h{'1'}, but that both are references to the same array, namely @a. What you probably want is:

for my $i ( 1 .. 2 ) {
    $h{"$i"} = $a[$i - 1];
}

which is equivalent to this:

$h{'1'} = $a[0];   # i.e., $a1_ref
$h{'2'} = $a[1];   # i.e., $a2_ref

which makes $h{'1'} a reference to @a1 and $h{'2'} a reference to @a2.

Incidentally, you might find it helpful to use the notations [ ... ] and { ... } to create references to anonymous arrays and hashes (respectively). Since you never use @a1 and @a2 except via $a1_ref and $a2_ref, you might as well create the latter directly:

my $a1_ref = [ 'a1', 1, 1, 1 ];   # reference to a new array (no name needed)
my $a2_ref = [ 'a2', 2, 2, 2 ];   # ditto

Edited for updated question: To copy an array, you can write:

my @orig = (1, 2, 3);
my @new = @orig;

or:

my $orig_ref = [1, 2, 3];
my $new_ref = [@$orig_ref]; # arrayref -> array -> list -> array -> arrayref

In your case, if I understand you correctly, you need to perform a slightly "deep" copy: you don't just want two arrays with the same elements, you want two arrays whose elements are references to distinct arrays with the same elements. There's no built-in Perl way to do that, but you can write a loop, or use the map function:

my @orig = ([1, 2, 3], [4, 5, 6]);
my @new = map [@$_], @orig;

So:

for my $i ( 1 .. 2 ) {
    $h{"$i"} = [map [@$_], @a];
}
like image 132
ruakh Avatar answered Sep 24 '22 22:09

ruakh