Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

hash from sub directly into foreach loop

by jeanluca (Deacon)
on Jun 30, 2006 at 08:08 UTC ( [id://558527]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks

I tried to put a hash from a sub directly into a foreach loop, like this
#! /usr/bin/perl use strict ; use warnings ; foreach ( keys &testa ) { print "key is $_\n" ; } sub testa { my %s ; $s{'a'} = 10 ; $s{'b'} = 20 ; $s{'c'} = 30 ; return %s ; }
this looks like good perl programming to me, but it doesn't work however :(
(It makes me feel like a beginner)
Any suggestions ?

Thnx LuCa

UPDATE: I've update the sub and replace % into $

Replies are listed 'Best First'.
Re: hash from sub directly into foreach loop
by davido (Cardinal) on Jun 30, 2006 at 08:33 UTC

    There are a few problems. One is that %s{'a'} = 10; won't compile. You mean to say, $s{'a'} = 10;

    The next problem is that testa() returns a flat list of keys and values, not a hash. You could re-hashify them like this:

    %{ { testa() } }

    This takes the return value of testa() (a flat list of keys interlaced with values), absorbs that list into an anonymous hash (the inner set of {...} does this), and then dereferences that anonymous hash ref (the outter %{ ..... } does this).

    But even then you still have a problem. Your loop will print a list of keys, sure enough. But how are you going to access the values if nothing is holding onto that hash ref?

    Try this instead:

    while( my( $key, $val ) = each( %{ { testa() } } ) { print "Key: $key\tValue: $val\n"; }

    ...or better yet, pass by reference, as described in perlsub:

    while( my( $key, $val ) = each( %{ testa() } ) { print "Key: $key\tValue: $val\n"; } sub testa { my %s = ( a => 10, b => 20, c => 30 ); return \%s; }

    Dave

      sorry for all the confusion about the typo.

      But thnx for the %{ { &testa } } that does the trick!
      I guess it might be very usefull to study the perlsub (how do you guys make this a link, where is it documented, I've search the docs already a couple of times ?)!!

      LuCa

        You're welcome, but I did say %{ { testa() } }, not %{ { &testa } }. Your specific example code doesn't bump into the difference, but there is a difference. It's just good to be in the habit of using the subroutine() method of calling subs, instead of the Perl4-ish (and sometimes confusing) &subroutine method.

        As for how to link to perlsub, see About the PerlMonks FAQ, and specifically, What shortcuts can I use for linking to other information?. ...but first read perlsub; that's a much more important step toward your understanding Perl.


        Dave

Re: hash from sub directly into foreach loop
by davidj (Priest) on Jun 30, 2006 at 08:17 UTC
    First of all, the syntax in the sub is incorrect:
    %s{'a'} = 10 ; %s{'b'} = 20 ; %s{'c'} = 30 ;
    should be
    $s{'a'} = 10 ; $s{'b'} = 20 ; $s{'c'} = 30 ;
    anyway, the following change will work for you:
    #!/usr/bin/perl use strict ; use warnings ; foreach ( keys %{&testa} ) { print "key is $_\n" ; } sub testa { my $s = () ; $s->{'a'} = 10 ; $s->{'b'} = 20 ; $s->{'c'} = 30 ; return $s ; }
    hope this helps,
    davidj

      Note that:

      my $s = ();

      is equivelent to

      my $s = (undef);

      which is equivelent to:

      my $s;

      The first use of a hash ref autovivifies the referred hash making the previous assignment redundant (and misleading). Consider:

      use strict; use warnings; use Data::Dump::Streamer; my $s = (); Dump ($s); $s->{'a'} = 10 ; Dump ($s);

      which prints:

      $VAR1 = undef; $HASH1 = { a => 10 };

      and note that the contents of $s changes from an undefined value to a hash ref.

      If you really want to indicate intent with an assignment use:

      my $s = {};

      DWIM is Perl's answer to Gödel
      nope, the sub should return a hash and not a hash reference. It should be the same as with
      foreach( keys CGI::Vars() )
      because that is what I'm trying to do!

      LuCa

        You can't "return a hash" from a subroutine, you can only return a list, the effect of return %hash is to flatten the hash into a list of key => value pairs. Thus the effect of the the three following subroutines is similar (the order of the hash keys in the first aside:)

        sub foo { my %foo = ( Foo => '1', Bar => '2'); return %foo; } + sub bar { my @bar = qw(Foo 1 Bar 2); return @bar; } + sub baz { return 'Foo','1','Bar','2'; } + print foo(),"\n"; print bar(),"\n"; print baz(),"\n";

        This is why people are telling you to return a hash reference as this is the only way to retain the, er, hashiness after the appropriate dereferencing.

        /J\

        Please show working code which does what you're trying to do. When I try the following, it doesn't work:

        Q:\>perl -MCGI -le "foreach( keys CGI::Vars() ) { print }" Type of arg 1 to keys must be hash (not subroutine entry) at -e line 1 +, near ") ) " Execution of -e aborted due to compilation errors.

        When I try the following, which the documentation and davidj suggest, it works (in the sense of not being a syntax error). But that works by returning a hash reference:

        Q:\>perl -MCGI -le "foreach( keys %{ CGI::Vars() }) { print }" Q:\>
Re: hash from sub directly into foreach loop
by crabbie_upk (Initiate) on Jul 01, 2006 at 00:30 UTC
    Hi, I think here is the code you must be looking for.
    #!/usr/bin/perl use strict ; use warnings ; foreach ( keys %{&testa} ) { print "key is $_\n" ; } sub testa { my $s ; $s->{a} = 10 ; $s->{b} = 20 ; $s->{c} = 30 ; return $s ; }
    Cheers, Udaya.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://558527]
Approved by davidj
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-23 21:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found