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

I'm new to Perl and am having a hard time working with hashes.

I have hash from a module successfully being passed into a function in another module as @_. I can Data::Dumper it to the screen. I thought I had success by simply being able to get the hash into my function. However, I can't figure out what to do next.

If I say:

sub test_parser(\%) { use Data::Dumper; print Dumper(@_); }

...the hash prints to the screen fine. But now I need to access the hash. It's a hash of hashes. So I figured I'd do something like this:

%mytest = @_

...so I could then work with at as a hash inside my function. But this does not work.

How can I pass a hash into a function and then get it back into a hash, or a reference or whatever, that I can work with?

I need to get @_ into a form like %myhash, so I can run foreach something like this:

%myhash = @_; #this is where the problem is!! foreach $key (keys %myhash) { %subhash = %{$myhash{$key}}; foreach $subkeys (keys %subhash){ $subkey_val = $subhash{$subkeys}; #print "$subkeys and $subkey_val\n"; if ($subkeys eq "competitor_firm" && $subkey_val eq ""){ delete $competitors_only{$key}; } } }

What's inside the above hash isn't so important. The main thing is that I need %myhash to be assigned the value of the hash that's inside @_. I have this routine running elsewhere in a module where I successfully duplicated a hash I needed to delete some values from. In case where I have the above routine working fine, I have this:

%myhash = %myoriginalhash;
SUMMARY: How do I take a hash being passed into a function as @_ and convert it to a hash I can do something with, like %myhash?

Thanks

Doug

Replies are listed 'Best First'.
Re: Trouble passing hash into function
by GrandFather (Saint) on Sep 05, 2007 at 22:57 UTC

    Are you passing the hash:

    use strict; use warnings; use Data::Dump::Streamer; my %hash = (a => 1, b => 2, c => 3); printHash (%hash); sub printHash { my %subHash = @_; print "$_ => $subHash{$_}\n" for keys %subHash; }

    Prints:

    c => 3 a => 1 b => 2

    or a reference to the hash:

    ... printHash (\%hash); sub printHash { my ($subHash) = @_; print "$_ => $subHash->{$_}\n" for keys %$subHash; }

    which prints as above. Or are you doing something else? If the snippets above don't clear the problem up, generate a similar sample demonstrating the problem and show it to us.


    DWIM is Perl's answer to Gödel
      Hmmm...I tried to get my head around references and hard references. I thought a hard reference has the \ in front of it. I was passing the hash, as I posted just a minute ago, with the \ infront of it.

      Can you explain the difference between "my %subhash" and "my (%subhash)" in your examples? I would have never in a million years (well, maybe) gotten to the point where I would tried parenthesis around a variable. They look optional to me.

      Regardless, I took off the \ where I passed the hash to the function...and it worked. I'm very relieved at the moment, but have no understanding about why this works, which is troubling after trying so hard to understand this.

      Thanks again!

      Doug

        For the low down on Perl references see perlref. You will probably find that perlsub helps too.

        The important bits are:

        The Perl model for function call and return values is simple: all functions are passed as parameters one single flat list of scalars

        and:

        Any arrays or hashes in these call and return lists will collapse, losing their identities

        in:

        my (...) = @_;

        the () provides a list context for the assignment so the elements in @_ are assigned in turn to the variables in (...). In the sample code there happens to be only one element in the list and we could instead have used one of:

        my $hash = $_[0]; my $hash = shift;

        instead. If you omit the (), then the assignment sees a scalar and assigns the number of elements in @_ to $hash rather than the contents of the first element.


        DWIM is Perl's answer to Gödel

        You would have to put a backslash in front of it normally, but because you've prototyped your sub Perl takes the reference for you behind the scenes and you receive that ref in $_[0] rather than the normal behavior of the hash being flattened into a list and you getting the key/value pairs in @_.

        Of course one might feel inclined to yet again comment on the undesirability of prototypes, but I'm getting weary of doing so . . .

Re: Trouble passing hash into function
by FunkyMonk (Bishop) on Sep 05, 2007 at 22:53 UTC
    SUMMARY: How do I take a hash being passed into a function as @_ and convert it to a hash I can do something with, like %myhash?
    If that's what you really want to do, you don't have to do very much at all
    hashy( %x ); sub hashy { my %myhash = @_ }

    That should do what you want.

      That's what I thought would work but here is what's happening:
      sub test_parser { use Data::Dumper; #print Dumper(@_); my %test = @_; print Dumper(%test); }
      If I comment out the second print and uncomment the first print, the @_ dumps fine. When I try to set %test, I get this error:

      Reference found where even-sized list expected at Debugger.pm line 8.
      I'm sending the hash from a master .pl file into the function like this:

      Debugger::test_parser(\%competitors_master);
      What else could be wrong?

      Thanks,

      Doug

        You are passing a hash reference, not a hash (which gets flattened into a list).

        The first dump works as expected because it sees a list containing one element which is the reference to the hash you passed in.

        The my %test = @_; and generates an error because @_ contains only one element - the reference to the hash. Instead you should my $test = shift; and work with the reference.


        DWIM is Perl's answer to Gödel