1

I am a newbie in Perl and trying out few stuffs.One thing I noticed is if one wants to pass an array as a value of a hashmap key one way of doing it is to pass it by reference. As follows

$hash_map{key} = \@arr

Is there any way to pass the array by value directly? Thanks

Always_Beginner
  • 2,546
  • 6
  • 25
  • 33

2 Answers2

5

A hash maps strings (keys) to scalar values. A value in a hash can only ever be a scalar.

An array is not (by definition!) a scalar. The best way to get a scalar value which represents that array is to take the reference to that array. And that's what your code does. This is how you should do it.

There are other ways to create a scalar value to represent an array. You could, for example, use join() to create a string from the elements of the array. But that would be very fragile as you would need to find a separator character that doesn't appear in any of the elements.

Far better to just take a reference as you are already doing.

Update: To clarify, there are three way to do this with references.

  • $hash{key} = \@array - takes a reference to the array and stores the reference in $hash{key}.
  • $hash{key} = [ @array ] - unrolls the array into a list, creates a new array using that list as the elements and returns a reference to this new array (effectively copying the array).
  • @{$hash{key}} = @array - this also takes a copy of the array and stores a reference to the copy.
Dave Cross
  • 68,119
  • 3
  • 51
  • 97
1

The following works for me just fine under perl 5.10 and 5.14:

use strict;
use Data::Dumper;

my @array= qw(foo 42 bar);
my %hash;
@{ $hash{key} } = @array;
$hash{key} = [ @array ]; #same as above line
print Dumper(\%hash,$hash{key}[1]);

outputs (your order may vary):

$VAR1 = {
          'key' => [
                     'foo',
                     '42',
                     'bar'
                   ]
        };
$VAR2 = '42';

I prefer the @{ $hash{key} } syntax because you can push/pop with it, i.e.

push @{ $hash{key} }, "value";

which is surprisingly handy (for me anyway)
also, with this syntax you are copying the array and not just putting a reference to it, meaning you can change the original array without impacting the hash

Nullman
  • 4,179
  • 2
  • 14
  • 30
  • That syntax works. And, as you can see, it does exactly the same thing as `$hash{key} = \@list`. But which option is easier to understand? `@{ $hash{key} }` looks pretty noisy to me :-) – Dave Cross Aug 23 '17 at 14:39
  • 2
    @DaveCross I don't think it is quite the same as it's copying the array – Chris Turner Aug 23 '17 at 14:43
  • @DaveCross thanks for clearing it up. i edited the answer to reflect why i prefer my syntax – Nullman Aug 23 '17 at 14:43
  • @ChrisTurner: Yes. you're right. `@{$hash{key}} = @array` is the same as `$hash{key} = [ @array ]`, but (slightly) different to `$hash{key} = \@array`. – Dave Cross Aug 23 '17 at 14:48
  • @Nullman: `@list` is a terrible name for that variable. It's an array, not a list :-) – Dave Cross Aug 23 '17 at 14:49
  • @DaveCross 99% of my points are from answering about python, i got used to writing "list" :) – Nullman Aug 23 '17 at 14:50
  • @Nullman: If you want a copy, just use `[@array]` instead of `\@array`. – Dave Cross Aug 23 '17 at 14:50
  • @Nullman: In Perl, lists and arrays are very different things. – Dave Cross Aug 23 '17 at 14:51
  • @DaveCross yes, but what about things like push/pop? i would prefer a uniform syntax to avoid confusing the next guy (and myself in x years) – Nullman Aug 23 '17 at 14:52
  • `@{ $hash{key} } = @array;` implies the array already exists, so it has poor readability. `$hash{key} = \@array;` is far more readable in that situation. – ikegami Aug 23 '17 at 16:33
  • @ikegami as ChrisTurner pointed out, those two are not the same. – Nullman Aug 23 '17 at 16:54
  • but the poster specifically asked `if one wants to pass an array as a value`, which my answer is – Nullman Aug 23 '17 at 16:56
  • I was commenting on your comment that `@{ $hash{key} } = @array;` is better than `$hash{key} = \@array;` *for reasons of readability*. /// Even if you want to make a copy, `@{ $hash{key} } = @array;` is not as clear as `$hash{key} = [ @array ];` (shallow copy) or `$hash{key} = dclone(\@array);` (deep copy). – ikegami Aug 23 '17 at 16:58
  • @ikegami this is true, but i personally prefer not to mix syntax int he same script and `@{ $hash{key} }` lets me push/pop – Nullman Aug 23 '17 at 17:01
  • It's unfortunate that you don't strive for readable code instead :( That's the core of good programming. Readable code is maintainable code, verifiable code, etc, etc, etc. Different things should look different. – ikegami Aug 23 '17 at 17:01
  • @ikegami lets agree to disagree. i have updated my answer to reflect both syntaxes. – Nullman Aug 23 '17 at 17:07
  • Re "*lets agree to disagree*", I'm confused?!? You just agreed in your previous comment! ("*[`@{ $hash{key} } = @array;` is not as clear as `$hash{key} = [ @array ];`] is true*") – ikegami Aug 23 '17 at 17:08
  • @ikegami i disagree that mixing syntaxes to access the same thing is more readable, but i do agree that, on its own, [@array] is more readable, and it IS a correct answer in any case so i added it to my answer. – Nullman Aug 23 '17 at 17:10
  • Using `@{ $hash{key} } = @array;` near `push @{ $hash{key} }, ...;` actually makes `@{ $hash{key} } = @array;` *even less readable* than if it wasn't near `push @{ $hash{key} }, ...;` and the proximity actually reinforces the incorrect implication that the array already exists. Maybe you don't understand what "readability" means? It means the ease by which the intention of the code is understood. By camouflaging one thing as another, you are reducing readability. One might even say "intentionally misleading"! That's the very opposite of readability. – ikegami Aug 23 '17 at 17:13