Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

parse hash to sub

by atnonis (Monk)
on Jul 15, 2003 at 17:06 UTC ( [id://274481]=perlquestion: print w/replies, xml ) Need Help??

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

hello monks!
i have a problem parsing a hash into a sub
new_packages($fcount,%new_db); sub new_packages { my %packages = $_[1]; print "Found $_[0] packages for download: $_\n" if ($fcount > 1); print "Found $_[0] package for download: $_\n" if ($fcount == 1); print "Which one would you like to install?:\n"; foreach my $key (keys (%packages)) { print "$key) $packages{$key} \n" } }
i get the following error:
Odd number of elements in hash assignment at ./slackup.pl line 49. Use of uninitialized value in concatenation (.) or string at ./slackup +.pl line 50. Found 3 packages for download: Which one would you like to install?: Use of uninitialized value in concatenation (.) or string at ./slackup +.pl line 54. 1)
the hash has these values:
%new_db = (1 => 'gedit-2.2.2-i386-1.tgz', 2 => 'ppp-3.4.1-i386-2.tgz')
where is my mistake i cant figure out!?

atnonis!

Replies are listed 'Best First'.
Re: parse hash to sub
by Trimbach (Curate) on Jul 15, 2003 at 17:24 UTC
    Because Perl automatically flattens hashes and arrays that are passed to subs, my %packages = $_[1]; doesn't access the entire %new_db hash, but only the first key of %new_db, which is why you're getting the odd number of elements error.

    Do it this way instead:

    new_packages($fcount,\%new_db); sub new_packages { my %packages = %{$_[1]}; ...
    By passing %new_db as a hash-reference, $_[1] refers to the hash-ref, which is then de-referenced into the %packages hash like you want.

    Most all of the time if you need to pass an array or hash into a sub you'll want to pass it by reference, not by value. :-)

    Gary Blackburn
    Trained Killer

Re: parse hash to sub
by jsprat (Curate) on Jul 15, 2003 at 17:25 UTC
    Parameters to a sub are flattened into a single list. More information can be found at perlsub.

    In reference to your question, either pass a reference or shift off the first item, then assign to your hash - ie:

    my $count = shift; %packages = @_;

    HTH...

Re: parse hash to sub
by bunnyman (Hermit) on Jul 15, 2003 at 17:30 UTC
     my %packages = $_[1];

    You can't do this. When you passed the %new_db to the sub, it got broken apart into a list, which looks like (1, 'gedit', 2, 'ppp'). So when you write $_[1] you are getting the first thing in that list, but you wanted to get the whole thing.

    You could fix it by writing @_[1..$#_] to get the whole thing, but that's pretty ugly. You could also write my ($count, %packages) = @_; which is less ugly and does the same thing.

    The best thing is to not even break the hash into a list at all. You can do that by passing a reference to the sub. Read about references at http://perldoc.com/perl5.8.0/pod/perlreftut.html

Re: parse hash to sub
by BrowserUk (Patriarch) on Jul 15, 2003 at 17:30 UTC

    You could also replace the first line of your sub with

    my ($fcount, %packages) = @_;

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller

Re: parse hash to sub
by blue_cowdawg (Monsignor) on Jul 15, 2003 at 17:35 UTC

    Fixed the code

    %new_db = (1 , 'gedit-2.2.2-i386-1.tgz', 2 , 'ppp-3.4.1-i386-2.tgz'); new_packages($fcount,\%new_db); sub new_packages { my %packages =%{ $_[1]}; print "Found $_[0] packages for download: $_\n" if ($fcount > 1); print "Found $_[0] package for download: $_\n" if ($fcount == 1); print "Which one would you like to install?:\n"; foreach my $key (keys (%packages)) { print "$key) $packages{$key} \n" } }

    Note that I changed your passing of the hash to passing of a reference to the hash and I de-reference it in the sub.

    Otherwise it is just going to look like an array of scalars.


    Peter L. BergholdBrewer of Belgian Ales
    Peter@Berghold.Netwww.berghold.net
    Unix Professional
      Just for the sake of completeness, I'll offer one more option - instead of dereferencing the hash reference passed in to new_packages, back into hash %packages, you could just accept the hash reference and use that to refer to your hash elements, like:
      sub new_packages { my $fcount = shift; # use shift instead of $_[0] my $packages_ref = shift; # use shift instead of $_[1] print "Found $fcount packages for download: $_\n" if $fcount > 1); print "Found $fcount package for download: $_\n" if $fcount == 1); print "Which one would you like to install?:\n"; foreach my $key (keys %{$packages_ref}) { print "$key) $packages_ref->{$key} \n"; } }
      Of course this code is completely untested, as your code probably was since I saw one or two problems with it.

      HTH.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-20 00:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found