Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
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 surveying the Monastery: (7)
As of 2024-04-16 06:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found