Perl: How to push key/value pair onto hashref and still retain reference
Asked Answered
K

2

6
$a = {b=>{c=>1}};   # set up ref
$b = $a->{b};       # ref the ref
$b .= (d=>1,e=>1);  # where we want to assign multiple key/val at once

At the end of it $a should look like:

  • {
      'b' => {
               'c' => 1,
               'd' => 1,
               'e' => 1
             }
    };
    

At the end of it $b should look like:

  • {
      'c' => 1,
      'd' => 1,
      'e' => 1
    }
    

Note: it would be the same as doing:

$b->{d} = 1;
$b->{e} = 1;

$b = { %$b, d=>1, e=>1 }; Is not desired because it creates a copy of $a and loses the reference.

Kansu answered 9/8, 2012 at 22:33 Comment(0)
P
8
%{$b} = ( d => 1, e => 1 );

You simply de-reference the anonymous hash-ref so it looks like a hash to the assignment operator.

You could even do this:

%{$b} = ( %{$b}, d => 1, e => 1 );

In these cases %{$b} is just really a visual convenience (though in some cases can be a syntactic disambiguation) for %$b.

...or you could do...

foreach ( qw/ d e / ) {
    $b->{$_} = 1;
}

Obviously you're probably not intending to assign the value of '1' to everything. So how about a slice:

@{$b}{ qw/ d e / } = ( 1, 1 );

Slices are discussed in perldoc perldata, but there's not really a good perldoc description of taking a slice of an anonymous hash. For that, you have to come to terms with all of the Perl documentation on references, and then extrapolate how to apply that to slice syntax. ...or check anonymous hash slices at PerlMonks.

Postnasal answered 9/8, 2012 at 22:44 Comment(4)
Yeah I looked at perldata before asking and I couldn't find anything specific - I'm glad you were able to decipher something from it. Frankly, I'm surprised %{$b} = ( %{$b}, d => 1, e => 1 ); worked (that it still applied changes to the referenced $a)Kansu
The bit about hashref slice helped me realize that the -> is not needed. With $_ being a hashref, I tried @_->{qw(key1 key2)} which produces a cryptic error message: Can't use an undefined value as a HASH reference This works: @{$_}{qw(key1 key2)}Scandinavian
@Scandinavian This may not have any bearing on what you were doing, but in your examples @_ and @$_ have two different meaningsKansu
@Kansu I followed the rule “sigil tells type of return value, brackets tell type of variable” (%hash, $hash{'item'}, @hash{qw(i t e m s)}), and knowing that -> does dereference, my attempt was rational. Only when Perl started to complain, I realized that “if you want slice, just use multiple keys and change sigil” does not work with hashrefs. Then I realized that Perl probably interprets @_->{…} as incorrect use of variable @_.Scandinavian
S
7

Use the hash slice notation.

 @$b{"d","e"} = (1,1);

 %newdata = (d => 1, e => 1);
 @$b{keys %newdata} = values %newdata;
Skaggs answered 9/8, 2012 at 23:10 Comment(1)
+1, Ahh hash slices, of course. Both answers were what I needed - I seleced David's because of keeping keys/vals together during assignment all in one line. - Thanks, mobKansu

© 2022 - 2024 — McMap. All rights reserved.