Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How to get the key - value names from a hash

by Scotmonk (Sexton)
on Nov 29, 2019 at 20:12 UTC ( [id://11109448]=perlquestion: print w/replies, xml ) Need Help??

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

Dear fellow monks, your novice here.
I am trying to understand what goes on behind the scenes with the code posted below.
I keep getting
Use of uninitialized value in print at map001.pl line 61. (and at line 81)
How do I get the code to tell me the names of the key - value pairs so that I can reference them ?
# Perl program to demonstrate the # splitting into the hash #!/usr/bin/perl use strict; use warnings; # variables used for computations my $linecount; my $start = time; my $column_count; my $file_errors = 0; my %distance; my %consec_two; my %consec_three; my %adj_row; my @prev; #----------------------------------------------------- my @items = (2,14,7,17,1,12,3,4,11,5,13,6,8,10,9,16,15,18); print "@items\n\n"; my @wrongsort = sort @items; print "@wrongsort\n\n"; @items = map {sprintf '%02u', $_ } @items; print "@items\n\n"; @items = sort @items; print "@items\n\n\n"; $column_count = @items; my ($odd)=(0); my ($even)=(0); print "Column Count = ","$column_count\n"; map {$_ % 2 ? $odd++ : $even++} @items; print "Odd = ","$odd\n"; print "Even = ","$even\n"; print "\n\n"; my %odd_even; print "\%odd_even hash contents \t\t", %odd_even, "\n\n"; + $odd_even{"$odd $even"}++; print "\%odd_even hash contents \t\t", %odd_even, "\n\n"; print "\%odd_even contents \t\t", $odd_even{0}, "\n\n"; # compute average for each row # first adding them all my %average; my $sum; map {$sum += $_} @items; my $avg = $sum / @items; $avg = ($avg - int($avg)) >= 0.5 ? int($avg) + 1 : int($avg); $average{$avg}++; print "AVERAGE hash contents \t\t", %average, "\n\n"; print "AVERAGE hash contents \t\t", $average{0}, "\n\n";

thankyou

Replies are listed 'Best First'.
Re: How to get the key - value names from a hash
by haukex (Archbishop) on Nov 29, 2019 at 20:34 UTC

    To help figure things out, I very strongly recommend you clean up your code - you've got some stray indentation, a whole bunch of unused variables and ones irrelevant to the question (Update: and lots of whitespace), and in a few cases the order of statements is a bit confusing (e.g. defining $odd and $even in between the use of $column_count). Also, lines 61 and 81 are not producing the warning, as you said. Fixing these things will help people who are trying to help you.

    Second, see the Basic debugging checklist, in this case the fourth point: use Data::Dumper or Data::Dump to look at your data structures. I've taken the liberty of doing all the above for you:

    #!/usr/bin/env perl use strict; use warnings; use Data::Dump; my @items = (2,14,7,17,1,12,3,4,11,5,13,6,8,10,9,16,15,18); @items = map { sprintf '%02u', $_ } @items; dd @items; @items = sort @items; dd @items; my ($odd,$even)=(0,0); $_ % 2 ? $odd++ : $even++ for @items; print "Odd = $odd, Even = $even\n"; my %odd_even; $odd_even{"$odd $even"}++; dd \%odd_even; # { "9 9" => 1 } dd $odd_even{0}; # undef my $sum; $sum += $_ for @items; my $avg = $sum / @items; $avg = ($avg - int($avg)) >= 0.5 ? int($avg) + 1 : int($avg); my %average; $average{$avg}++; dd \%average; # { 10 => 1 } dd $average{0}; # undef

    So the reason you're getting that warning is because each of your hashes have only one key, each of which is not "0". If you want to iterate over a hash, see keys, values, and each. Personally, my code for iterating over a hash typically looks something like this:

    for my $key (sort keys %hash) { my $value = $hash{$key}; }

    Note that while your method of doing a numeric sort may work in this case, it will break on 3-digit and longer numbers. A numeric sort in Perl is written as: sort {$a<=>$b} @array.

    Also, a nitpick: using map only for its side effects can be a little confusing, so I've changed it to a for loop instead.

    Update 2: Note that ($avg - int($avg)) >= 0.5 ? int($avg) + 1 : int($avg) can also be written as: use POSIX 'lround'; $avg = lround($avg);

      First, thankyou for your response, I really do appreciate it

      Regarding the mess of the code, I am not a programmer at all, I am a scientist of the neuro kind.

      I am spending my spare time trying to learn Perl, but I am finding it very difficult.
      There is no group near me in Glasgow, and the websites that I use to try to understand often quickly go over my head

      Often when I do copy code, it throws up errors on my machine, which is really frustrating

      I have found you guys very helpfull, in fact you are great
      Going forward I will take all advice given, including providing code that is tidy
      coincidentally, those indents are there only so I can read it better
      I have the Lama book, and as it says in there, Perl is difficult for beginners because so much goes on in the back ground
      for such little snippets of written code; thats very true

      I just want to understand what is going on in the background so I have been copying bits of code
      from various places and trying to work out step by step what is going on
      Those other variables were there because I was copying code in chunks and attmepting to work through
      I have a lot of numbers to record and compare and evaluate, so most of
      what I have to learn is arithmetic; i don't need to know much about whaty Perl does with letters

      You guys are patient with me, and I do appreciate that

        coincidentally, those indents are there only so I can read it better

        Coincidentally that's why we like indents too. Unlike Python, indents pretty much only serve to make code legible. (In Python they exist to aid legibility but also to indicate blocks of code, and scoping.)

        You might have a look at Perl::Tidy. It provides a utility that can clean up your formatting for you.


        Dave

        I am spending my spare time trying to learn Perl, but I am finding it very difficult.

        Yes, I understand, Perl's learning curve isn't exactly small, but once things start to click, IMHO it's a great language :-) (my favorite!)

        the websites that I use to try to understand often quickly go over my head

        You said you have the Llama book, that's good, if you're interested in more I can suggest Modern Perl, and see also So what is your Perl book "Trilogy" anyway?. And once you've gotten into Perl a little more, IMHO the Camel is a must.

        Going forward I will take all advice given, including providing code that is tidy coincidentally, those indents are there only so I can read it better

        Yes, I should have made it more clear that aside from those suggestions being helpful for those trying to help (especially standardized indentation), cleaning up your code will help you narrow down and focus on the issue you're seeing. In general, remove a line of code, if the problem goes away or changes, put the line back in, but if the problem doesn't change, then that line of code most likely wasn't relevant to the issue.

        I just want to understand what is going on in the background so I have been copying bits of code from various places and trying to work out step by step what is going on

        In that case, Data::Dumper or Data::Dump are great tools, I use them for watching my data and debugging all the time.

      What does dd mean in the above code ?

      thankyou
Re: How to get the key - value names from a hash
by davido (Cardinal) on Nov 29, 2019 at 22:35 UTC

    Line 61 and 81 in your pasted code are both blank lines. The actual line numbers you are seeing warning messages on are either probably 62, and 82 of what you posted.

    "How to get the key - value names from a hash":

    my %hash = (foo => 42, bar => 84); # Here is the easiest way: my @kv_pairs = %hash print "All keys and all values as a flattened list: ", @kv_pairs, "\n" +; # Ok, an even easier way: print "All keys and all values as a flattened list: ", %hash, "\n"; # +Because, list context. # Here is another way: while (my ($key, $value) = each %hash) { print "$key => $value\n"; } # Here is another way: my @keys = keys %hash; my @values = values %hash; for my $i (0.. $#keys) { # (fixed) print "$keys[$i] => $values[$i]\n"; } # And yet another: foreach my $key (keys %hash) { print "$key => $hash{$key}\n"; }

    The warnings you are seeing on line 62 of the code you posted, and line 82:

    On line 82 you reference $average{0}. That means that $avg must, at least one time, have equated to zero. Put a print statement like this: print "avg: $avg\n", "\$avg is exactly 0:", ($avg == 0 ? " yes" : " no"), "\n"; on the line immediately following where $avg gets defined. I'll bet you don't see any exact zeros.

    On line 62 you are printing "$odd_even{0}", but nothing ever puts an element names '0' in your %odd_even hash. Why do you think that after creating a hash key that looks like "9 9" you could then expect to be able to print a hash element named 0?

    I think that spending 30 minutes reading perlintro and possibly another ten minutes skimming perldata would clear things up. As I've learned other languages I've often wished those languages had such good documentation.


    Dave

Re: How to get the key - value names from a hash
by LanX (Saint) on Nov 29, 2019 at 20:24 UTC
    Which is line 61?

    You could try to cook down the problem to a small example.

    Be warned: with this amount of badly indented code many tend to not reply.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2024-03-28 15:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found