jerry.hone has asked for the wisdom of the Perl Monks concerning the following question:

I've 'borrowed' the following code...
%a = ( a => 1, b => 2, c => 3, d => 4, e => 5 ); %b = ( c => 9, d => 16, f => 36 ); $A=\%a; @$A{keys %b} = values %b;
which works brilliantly to merge hash b into hash a. What I don't understand is the syntax! Can someone explain what's actually going on here please.

Replies are listed 'Best First'.
Re: Hash merging!
by ambrus (Abbot) on Apr 26, 2005 at 08:37 UTC

    I think it's just an overcomplicated version for this:

    @a{keys %b} = values %b;

    (Update: changed $ silgil to @.)

      Which itself can be reduced to %a = (%a, %b);. Granted if you wanted to preserve the elements of either hash, you would have to use the above method. I presume the behavior is undefined, but on my machine:

      %a = (%a, %b); # common elements contain %b's values %a = (%b, %a); # common elements contain %a's values

        Yes, it is simpler, but it seems that @a{keys %b} = values %b; is consistently faster. A quick mesurement shows that

        perl -we 'use Time::HiRes "time"; %a = map rand, 1 .. (1<<18); %b = ma +p rand, 1 .. (1<<18); warn($t = time()); %a = (%a, %b); warn time() - + $t; warn 0+keys(%a);'
        runs in 2.8s, while
        perl -we 'use Time::HiRes "time"; %a = map rand, 1 .. (1<<18); %b = ma +p rand, 1 .. (1<<18); warn($t = time()); @a{keys %b} = values %b; war +n time() - $t; warn 0+keys(%a);'
        in 1.0s.
Re: Hash merging!
by inman (Curate) on Apr 26, 2005 at 08:40 UTC
    You can use a hash slice to merge the hashes without the need for a reference.

    @a{keys %b} = values %b;

Re: Hash merging!
by eibwen (Friar) on Apr 26, 2005 at 07:59 UTC

    $A = \%a; creates a reference to the hash %a. References are akin to c pointers, but I'd recommend the tutorials and super search for more.

    @$A{keys %b} = values %b; sets the list of (keys %b) equal to the list of (values %b) as hash elements of $A, which is a reference to %a.

    You may also be interested in the PLEAC - Merging Hashes codes.

    HTH

      Need to explain myself more...
      I understand pointers. It's the semantics of the @$A... line that's baffling me.
      I know values %b is returning and array
      Also keys %b is returning an array
      $A{array} doesn't seem to make sense and what exactly is the @ doing on the front.

        my %hash; # the % sigil denotes a hash $hash{'element'} = 1; # the $ sigil denotes a scalar value (the 'eleme +nt' element of %hash)

        Similarly, the @ sigil in @$A{keys %b} denotes list context. I believe it interpolates as (verified):

        @$A{(c,d,f)} = (9, 16, 36);

        Which is essentially the same thing as:

        $A{c} = 9; $A{d} = 16; $A{f} = 36;

        Given that $A = \%a, you could skip the reference:

        $a{c} = 9; $a{d} = 16; $a{f} = 36;

        @varname{LIST} is a hash slice, a list of all the values of %varname for the keys in LIST.