InfiniteSilence has asked for the wisdom of the Perl Monks concerning the following question:

The following is from an e-mail I sent to an individual who wrote an online perl tutorial

--begin snip--

I was looking at your site ( www.sysarch.com ... hash_slices.txt) for good examples of hash slices when I came across the following code:

@array = qw( a b c d ) ; @array{ @array } = ( [ @array ] ) x @array ;
With the explanation:
...this means the hash %array looks like this: %array = ( 'a' => [ 'a', 'b', 'c', 'd' ], 'b' => [ 'a', 'b', 'c', 'd' ], 'c' => [ 'a', 'b', 'c', 'd' ], 'd' => [ 'a', 'b', 'c', 'd' ], ) ;
Actually this is FALSE. Your original code does not create four separate anonymous array references but four entries that point to the same hash reference. Debugging reveals the error:
DB<1> n main::(-e:1): @array = qw( a b c d ) ;@array{ @array } = ( + [ @array ] ) x @array ; print $array{'a'}->[1]; DB<1> main::(-e:1): @array = qw( a b c d ) ;@array{ @array } = ( + [ @array ] ) x @array ; print $array{'a'}->[1]; DB<1> x %array 0 'a' 1 ARRAY(0x1d7f550) 0 'a' 1 'b' 2 'c' 3 'd' 2 'b' 3 ARRAY(0x1d7f550) -> REUSED_ADDRESS 4 'c' 5 ARRAY(0x1d7f550) -> REUSED_ADDRESS 6 'd' 7 ARRAY(0x1d7f550) -> REUSED_ADDRESS DB<2>
And a test confirms this:
C:\>perl -e "@array = qw( a b c d ) ;@array{ @array } = ( [ @array ] ) x @array ; $array{'a'} +->[1] = 'FOOBAR'; print $array{'a'}->[1]; print $array{'b'}->[1];" FOOBARFOOBAR
--end snip--

It was a bummer that I could not use the syntax given to get a hash of anonymous arrays that are different. Here's my question, how do you get four anonymous arrays using similar syntax?

Celebrate Intellectual Diversity

Replies are listed 'Best First'.
Re: Getting different anonymous arrays
by broquaint (Abbot) on Sep 08, 2003 at 16:06 UTC
    Looks like a good case for map
    my @array = qw( a b c d ) ; my %hash; @hash{ @array } = map [@array], @array; print "$_ => $hash{$_}\n" for keys %hash; __output__ a => ARRAY(0x8107e30) b => ARRAY(0x8107f5c) c => ARRAY(0x8107fa4) d => ARRAY(0x8107fec)
    Or without constructing a list
    $hash{$_} = [@array] for @array;
    So in the first example we create a new anonymous array of @array for every element in @array and then assign the resulting list to the hash slice. In the second example it's much the same except we iteratively assign each new anonymous array.

    See. map for more information.
    HTH

    _________
    broquaint

Re: Getting different anonymous arrays
by welchavw (Pilgrim) on Sep 08, 2003 at 19:56 UTC
    Just a slight variant on the already provided map approach.
    @array = qw( a b c d ) ; $array{$_} = [@array] for @array;
Re: Getting different anonymous arrays
by flounder99 (Friar) on Sep 08, 2003 at 16:29 UTC
    I thought I would give it a test.
    Could someone explain this?
    use Data::Dumper; use strict; my @array; my %array; @array = qw( a b c d ) ; @array{ @array } = ( [ @array ] ) x @array ; print Data::Dumper->Dump([\%array], ["*array"]); __OUTPUT__ %array = ( 'c' => [ 'a', 'b', 'c', 'd' ], 'a' => $array{'c'}, 'b' => $array{'c'}, 'd' => $array{'c'} );
    I don't get it either!
    perl -v This is perl, v5.8.0 built for MSWin32-x86-multi-thread (with 1 registered patch, see perl -V for more detail) Copyright 1987-2002, Larry Wall Binary build 806 provided by ActiveState Corp. http://www.ActiveState. +com Built 00:45:44 Mar 31 2003 ---snip---

    --

    flounder

      ( [ @array ] ) x @array ;
      Make N copies of [ @array ]
      @array{ @array } = ( [ @array ] ) x @array ;
      Do the hash assign of the N copies. This is all obvious so far, now for the trickier bit, the output
      %array = ( 'c' => [ 'a', 'b', 'c', 'd' ], 'a' => $array{'c'}, 'b' => $array{'c'}, 'd' => $array{'c'} );
      Unusual, you say, that the key 'c' should get 'the original' and the rest get copies, but if we look at the ordering of the keys this makes sense
      shell> perl -le 'print keys %{{map {$_=>1} qw/a b c d/}}' cabd
      So as you may have guessed by now Data::Dumper's output shows that 'c' just happens to look like its got 'the original' due to the ordering of the hash. In reality they all point to the same anonymous array.
      HTH

      _________
      broquaint

      This is just a freeze/thaw way of getting back a structure which points at the same arrayref. If you built it like this:

      %array = ( 'a' => ['a','b','c','d'], 'b' => ['a','b','c','d'], 'c' => ['a','b','c','d'], 'd' => ['a','b','c','d'] );

      you would have four different anonymous arrays, not four refencences to the same array, as the original code created.

      Not sure if this answered your question, or if I even understood it, but there you go :).

        I just thought it was weird that the anonymous array was definded as the value of the hash key 'c' and all the rest of the hash keys have a value of its reference. It seems to me that the hash key 'a' would have been defined first and the other keys would have the value of its reference. I guess it doesn't matter -- they all point to the same anonymous array reference.

        I see what happens. if I add this line to my original program:

        print join ",", keys %array;
        I get an output of:
        c,a,b,d
        So Data::Dumper must just take the first key it gets from keys point it to the anonymous array reference and then have the rest of the keys point to it. That makes sense. You learn something new every day.

        --

        flounder