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

How can I pass two hashes to a subroutine that will return its calculations in a third hash?

EXAMPLE:
%majCodon = calMajCodon(%genes, %codonTotal);

20031018 Edit by Corion: Added formatting

Replies are listed 'Best First'.
Re: passing two hashs to a subroutine
by pg (Canon) on Oct 18, 2003 at 17:33 UTC

    Passing hash refs, and returning hash ref.

    Let's assume, we want to implement such an operation, it takes each pair from the first hash, if the same key exists in the second hash, sum them up. For those keys exist in hash2, but not hash1, forget about them. Then what you can do is:

    use Data::Dumper; use strict; my $h1 = {"a" => 1, "b" => 2}; my $h2 = {"c" => 1, "b" => 3}; my $ret = plus($h1, $h2); print Dumper($ret); sub plus { my $ret = {}; my ($hash1, $hash2) = @_; for (keys %$hash1) { if (exists($hash2->{$_})) { $ret->{$_} = $hash1->{$_} + $hash2->{$_}; } else { $ret->{$_} = $hash1->{$_}; } } return $ret; }
Re: passing two hashs to a subroutine
by demerphq (Chancellor) on Oct 18, 2003 at 22:04 UTC

    Well, you could use prototypes to do this.

    use Data::Dumper; sub two_hash(\%\%) { my ($genes,$totals)=@_; return { %$genes,%$totals } } my %foo=qw(1 2); my %bar=qw(A B); print Dumper two_hash(%foo,%bar);

    But I have this horrible feeling that my saying this is like giving a loaded gun to a baby to play with. Don't do it this way until you understand why I have this feeling.

    :-)


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


Re: passing two hashs to a subroutine
by The Mad Hatter (Priest) on Oct 18, 2003 at 17:49 UTC
    As pg said, use hash refs like so:
    %majCodon = calMajCodon(\%genes, \%codonTotal); sub calMajCodon { # To just use the hash refs (and save memory) ... my ($genes, $codonTotal) = @_; print $codonTotal->{startCodon}; # ... or to use as regular hashes. my %genes = %{$_[0]}; my %codonTotal = %{$_[1]}; print $codonTotal{startCodon}; # And to return a hash... return %majCodons; }
    See perlref.

    Update Fixed ambiguous use of shift as pointed out by the anony monk.

      Urg, ambiuous use of %{shift}. Instead, use:

      # ... or to use as regular hashes my %genes = %{+shift}; my %codonTotal = %{+shift}; # ... or even my %genes = %{$_[0]}; my %codonTotal = %{$_[1]};

      :)

Re: passing two hashs to a subroutine
by vek (Prior) on Oct 18, 2003 at 19:56 UTC

    To answer your immediate question, you've already got it right. Your example is exactly how you'd pass two hashes to a subroutine and get a hash as a result. That having been said, it's not the best way to do it mind you. As others have pointed out, using hash refs would certainly be the way to go here.

    Update: Er, don't know what I was smoking when I posted that. Please disregard.

    -- vek --
      To answer your immediate question, you've already got it right. Your example is exactly how you'd pass two hashes to a subroutine...

      Actually, that's wrong. Passing 2 or more hashes (or arrays) into a sub that way causes them to be flattened into a single list, which means it isn't possible to separate them once inside the sub.

      main::(-e:1): 1 DB<1> %h = ( a=>1, b=>2, c=>3 ); DB<2> %i = ( x=>1, y=>2, z=>3 ); DB<3> sub test{ my( %h, %i ) = @_; print '%h: ', scalar keys %h, ' % +i: ', scalar keys %i; }; DB<4> test( %h, %i ); DB<5> %h: 6 %i: 0

      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      Hooray!