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

Hi monks,

I use this below code, I am not getting output exactly, what i expect the value to be stored in hash

use Data::Dumper; %fruits=(); @arr = ([1,1],[1,2],[3,5],[6,7]); for (@arr) { $a = $_->[0]; $b = $_->[1]; $fruits{$a} = $b; } print Dumper(\%fruits);

I want the output format as like this:

$VAR1 = { '6' => 7, '1' => 1,2, '3' => 5 };

My input as mentioned in the above you may use any code or module. Please help the code.
Thanks in Advance.

Regards,
Gubendran.

Replies are listed 'Best First'.
Re: How to store this value in Hash ?
by jhourcle (Prior) on Mar 21, 2005 at 11:41 UTC
    Your output from Dumper is invalid -- you should be able to take the results, and send it to 'eval', which results in Odd number of elements in hash assignment. You'd probably want to use a hash of arrays --
    use Data::Dumper; my %fruits=(); my @arr = ([1,1],[1,2],[3,5],[6,7]); for (@arr) { push @{$fruits{$_->[0]}}, $_->[1]; } print Dumper(\%fruits);
Re: How to store this value in Hash ?
by gopalr (Priest) on Mar 21, 2005 at 12:33 UTC
    use Data::Dumper; @ar=([1,1],[1,2],[3,5],[6,7]); map {test($_->[0],$_->[1])} @ar; sub test { my ($k,$val)=@_; if (exists $hash{$k}) { $hash{$k} .= ','.$val ; } else { $hash{$k}=$val; } } print Dumper(\%hash);

    Output:

    $VAR1 = { '6' => 7, '1' => '1,2', '3' => 5 };
      There's two possible and different ways to do this.
      push @{$fruits{$a}},$b
      will create a hash-of-arrays where each hash element references an array.
      $fruits{$a} .= ','.$b ;
      will just concatenate all values($b) for a particular key ($a).
      The selection of one of these depends entirely on what is to be done with the hash after it has been populated. For computational purposes, dealing with a hash-of-arrays is (IMHO) easier than doing a series of splits on a value which was constructed by concatenating...
      The hash-of-arrays is easier to iterate through, whereas if you just need to print to output, concatenating might be a better option.

      Manav
Re: How to store this value in Hash ?
by tlm (Prior) on Mar 21, 2005 at 11:59 UTC
    Replace
    $fruits{$a} = $b;
    by
    push @{$fruits{$a}}, $b;
    the lowliest monk

    Update: Typo fixed. Thanks, Manav & Happy-the-monk.

Re: How to store this value in Hash ?
by ikegami (Patriarch) on Mar 21, 2005 at 16:10 UTC

    I see solutions to your problem, but since I don't see any explanation, I'll provide one.

    Your problems lies with the fact that hashes can only have a single value at any given key. However, those value can be an array (or hash) reference which may contain a list of items.

    One provided solution provided is:
    push @{$fruits{$a}},$b
    which is equivalent to:
    $fruits{$a} = [] unless $fruits{$a}; # create array, save ref
    push @{$fruits{$a}},$b

    People suggested you could also form a string representing the list of values:
    if (defined($fruits{$a})) {
       $fruits{$a} .= ','.$b;  # Add to existing list
    } else {
       $fruits{$a} = $b;       # Start new list
    }
    This isn't good if you're planning on manipulating the individual values, but it good if you're just going to print out the list without modification.

    One of the Perl docs refers to Array of Arrays (AoA). You should read up on those.

Re: How to store this value in Hash ?
by reasonablekeith (Deacon) on Mar 21, 2005 at 14:29 UTC
    as an aside, you shouldn't really use $a or $b, as they are the default variables used for rolling your own sort functions...
    perldoc -f sort
Re: How to store this value in Hash ?
by demerphq (Chancellor) on Mar 21, 2005 at 14:43 UTC

    Assuming you dont have undefined values or references as the values of @arr you can do this:

    use Data::Dumper; %fruits=(); @arr = ([1,1],[1,2],[3,5],[6,7]); for (@arr) { my ($k,$v)=@$_; if (ref $fruits{$k}) { push @{$fruits{$k}},$v; } else{ $v=[$fruits{$k},$v] if (defined $fruits{$k}); $fruits{$k}=$v; } } print Dumper(\%fruits); __END__ $VAR1 = { '6' => 7, '1' => [ 1, 2 ], '3' => 5 };

    Which is IMO a pattern perl programmers should be familiar with as it comes up fairly often. When only a few values will be lists the overhead of forcing each one to be an array can be unacceptable, but a hybrid works reasonably well. Imo generating stringified lists is not too desirable, but thats just me being a generalist, I suspect it could be a reasonable approach for some problems.

    ---
    demerphq

Re: How to store this value in Hash ?
by sh1tn (Priest) on Mar 21, 2005 at 11:25 UTC
    use strict; use Data::Dumper; my %fruits=(); my @arr = ([1,1],[1,2],[3,5],[6,7]); for (0..$#arr) { $fruits{$_} = $arr[$_] } print Dumper(\%fruits); __END__ STDOUT: $VAR1 = { '1' => [ 1, 2 ], '3' => [ 6, 7 ], '0' => [ 1, 1 ], '2' => [ 3, 5 ] };
    Update:
    ... for (0..$#arr) { $fruits{$arr[$_]->[0]} = $arr[$_]->[1] } ... # thus: $VAR1 = { '6' => 7, '1' => 2, '3' => 5 };
    Update:
    ... for (0..$#arr) { $fruits{$arr[$_]->[0]} = [@{$arr[$_]}[1..@{$arr[$_]}- +1]] } ...