http://www.perlmonks.org?node_id=11108480

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

Hello, i'm looking to manipulate an hash array and transform/insert it into a new hash, I am a bit unsure how to do this if anyone could help would appreciate it a lot

My Current hash array:

"1" => { "PRICE" => 0, "CODE" => "code value 1", "LABEL" => "RED", }, "2" => { "PRICE" => 0, "CODE" => "code value 2", "LABEL" => "RED", }, , "3" => { "PRICE" => 1, "CODE" => "code value 3", "LABEL" => "BLUE", },

What I want to the hash array to be changed/transformed to:

"RED" => { "PRICE" => 0, "CODE" => "code value 1", "LABEL" => "RED", }, { "PRICE" => 0, "CODE" => "code value 2", "LABEL" => "RED", }, "BLUE" => { "PRICE" => 1, "CODE" => "code value 3", "LABEL" => "BLUE", },

Replies are listed 'Best First'.
Re: hash array question
by choroba (Cardinal) on Nov 08, 2019 at 16:56 UTC
    The expected structure doesn't make any sense, have you tried to populate a hash by it and use Data::Dumper to visualise it?
    Odd number of elements in hash assignment at ...line 29. $VAR1 = { 'HASH(0x563b633597c8)' => undef, 'RED' => { 'PRICE' => 0, 'CODE' => 'code value 1', 'LABEL' => 'RED' }, 'HASH(0x563b63359750)' => 'BLUE' };
    You can't assing two values to a single key.

    If you want to assign an array reference to each key, though, it's doable:

    #!/usr/bin/perl use warnings; use strict; use Test::More; my %in = ( 1 => { PRICE => 0, CODE => 'code value 1', LABEL => 'RED' }, 2 => { PRICE => 0, CODE => 'code value 2', LABEL => 'RED' }, 3 => { PRICE => 1, CODE => 'code value 3', LABEL => 'BLUE' } ); my %out; push @{ $out{ $_->{LABEL} } }, $_ for values %in; is_deeply \%out, { RED => [ { PRICE => 0, CODE => 'code value 1', LABEL => 'RED' }, { PRICE => 0, CODE => 'code value 2', LABEL => 'RED',} ], BLUE => [ { PRICE => 1, CODE => 'code value 3', LABEL => 'BLUE', } ], }, 'same';
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
      Many thanks, this is what i'm looking for. Is it also possible to add a key to each sub array? Something like:
      RED => [ {KEYNAME =>[ PRICE => 0, CODE => 'code value 1', LABEL => 'RED'] }, { KEYNAME => [PRICE => 0, CODE => 'code value 2', LABEL => 'RED',}] ], BLUE => [KEYNAME => [ { PRICE => 1, CODE => 'code value 3', LABEL => 'BLUE', } ]]

        Also, an expression such as
            { KEYNAME => [ PRICE => 0, CODE => 'code value 1', LABEL => 'RED' ] }
        suggests you may be mistaking an array element for part of a hash key/value pair. The  => (fat arrow) operator is just a fancy comma (see Comma Operator), it does nothing | nothing in and of itself to form key/value pairs. The expression above is equivalent to
            { KEYNAME => [ 'PRICE', 0, 'CODE', 'code value 1', 'LABEL', 'RED' ] }
        (update: in which an anonymous array is initialized with a set of unrelated, i.e., unpaired, elements).


        Give a man a fish:  <%-{-{-{-<

        Sorry, I don't understand. After RED, you have two hashes in an array, but after BLUE, there's no hash, just an array. Also, are you sure you want to store the tuples in an array instead of a hash?

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: hash array question
by Eily (Monsignor) on Nov 08, 2019 at 16:53 UTC

    Where does the first hash come from? Maybe there's a way to get the data directly in the format you want, if the intermediate format (your first one) is useless.

    Otherwise something like this might help:

    # maybe you can directly iterate on the input, rather than iterate ove +r %first_hash # Get the contained hashes (which are the values of the top hash), bec +ause the keys are not used for my $subhash (values %first_hash) { my $key = $subhash->{LABEL}; # You have the key above, and the associated value is actually $subh +ash ... }

    Edit: this is really straightforward, so maybe the information your are missing is how to work with references (a hash within a hash is actually stored through a reference, ie an hashref).

    Edit 2: oh ++choroba is right, you can't just have multiple values for the same key. You need an intermediate array. Thanks to the magic of autovivification you can just write: push @{ $hash{$key} }, $value to add a new $value to the array stored at $key (and created it if needed).

Re: hash array question
by AnomalousMonk (Archbishop) on Nov 08, 2019 at 22:01 UTC