Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

arrays vs. lists referencing question

Tags:

perl

Two questions regarding the following code :


%h1 = {
    'key1' => ( 1, 2, 3 ),
    'key2' => ( 4, 5, 6 )
    };

%h2 = {
    'key1' => [ 1, 2, 3 ],
    'key2' => [ 4, 5, 6 ]
    };

print $(@h1{'key2'})[1];

Q1 : What is the difference between h1 and h2? Please don't say 'one is a hash of lists and another hash of arrays'... Rather, I want to know what that translates to in terms of usage.

Q2 : Why does the the reference $(@h1{'key2'})[1] in the print statement not compile? This is my thinking : I want access the array/list corresponding to 'key2' : @h1{'key2'}. Then I want to access the scalar at the index of 1 in that list/array : $(@h1{'key2'})[1]. Why is this wrong ? This variable referencing stuff is confusing.

like image 513
sriaudacity Avatar asked Nov 27 '22 22:11

sriaudacity


2 Answers

Neither of those work like you think. use strict and use warnings always.

%h1 = {
'key1' => ( 1, 2, 3 ),
'key2' => ( 4, 5, 6 )
};

You're trying to assign a hashref ( {} construct ) to a hash. It gets stringified into a scalar and is used as a key in %h1, with a value of undef. In addition, cause you're using lists ( () construct), it gets flattened and you're creating the hash:

%href = ( key1 => 1,
          2 => 3,
          key2 => 4,
          5 => 6,
        );

In the latter case, you correctly create your hash with array refs ( [] construct), but you're still assigning a href to the hash. You want to do:

%h1 = (
'key1' => [ 1, 2, 3 ],
'key2' => [ 4, 5, 6 ]
);

This creates %h1 in list context and your values in scalar context via reference.

like image 142
Oesor Avatar answered Dec 17 '22 03:12

Oesor


The difference: they're both wrong! :)

Lists are flat structures; you can't have lists of lists, you just get a (one-dimensional) list back.

References are scalars. So %h1 = { ... } doesn't make sense. What you're doing is just assigning a one-element list to %h1, which gets stringified and turned into a key. This is equivalent to

%h1 = ( 'HASH(0x1fb872a0)' => undef );

where the key is the stringified version of whatever memory address held that hash reference.

To make a hash of arrays, do this:

my %h1 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] );

If you want a reference to a hash of arrays, you can use:

my $ref = { key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] };

or

my $ref = \%h1;

Finally, to access your structure elements, you can use:

print $h1{key2}[1];

or

print $ref->{key2}[1];

In the latter case we use the -> operator to dereference the structure. For subsequent levels, -> is assumed, but you can also write

print $ref->{key2}->[1];

if you find that clearer.

To get the complete structure back from the reference (e.g. to use keys) you need to use another form of dereferencing:

my @keys = keys %$ref;    # or more explicitly %{ $ref }

To get at the full inner structure, it's the same thing:

my @a2 = @{ $ref->{key2} };

All of this is covered in full detail in the following excellent Perl docs:

  1. Perl references tutorial
  2. Perl references
  3. Perl data structures cookbook

and others.

like image 24
friedo Avatar answered Dec 17 '22 04:12

friedo