Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Output of hash

by catfish1116 (Beadle)
on Apr 23, 2019 at 21:16 UTC ( [id://1232919]=perlquestion: print w/replies, xml ) Need Help??

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

I have this as my code

while ( (@k, @v) = each %hash) { print "@k => @v \n"; }

and this is my output

6 18 => 50 150 => 3 9 => 7 21 => 91 273 => 9 27 => 1 3 => 4 12 => 34 102 => 89 267 => 76 228 =>

What do I have to do to get it like 4 => 12 ? TIA The Catfish

Replies are listed 'Best First'.
Re: Output of hash
by stevieb (Canon) on Apr 23, 2019 at 21:25 UTC
    use warnings; use strict; my %hash = (4 => 12, 34 => 102); while (my ($k, $v) = each %hash){ print "$k => $v\n"; }

    In other words, each() returns two scalar items. What's happening in your case, is that @k is taking both items being returned for each hash key/value pair on each iteration, so there's nothing ever in the @v array. Use scalars like I have instead.

Re: Output of hash
by AnomalousMonk (Archbishop) on Apr 23, 2019 at 22:35 UTC

    stevieb++ and johngg++ have explained the problem and its solution, but note also that this feature (yes, feature) is called "list flattening". Any lvalue array (or hash) in a list assignment will consume all remaining items in the assigned (RHS) list.

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -e "my ($w, $x, @y, @z); ($w, $x, @y, @z) = qw(Dubya Eks Why? Zee-List-Is-Flattened); dd 'w', $w; dd 'x', $x; dd 'y', \@y; dd 'z', \@z; " ("w", "Dubya") ("x", "Eks") ("y", ["Why?", "Zee-List-Is-Flattened"]) ("z", [])
    Try this with  %y (a hash) in place of the  @y array, and with any combination of scalar(s), array(s) or hash(s) in place of the  @z array.

    BTW, in the category of Stupid Hash Tricks, try this:

    c:\@Work\Perl\monks>perl -wMstrict -le "my %hash = (4 => 12, 34 => 102); ;; while (my %h = each %hash) { printf qq{%s => %s \n}, %h; } " 4 => 12 34 => 102

    Update: A solution using assignment to an array (update: could also be a hash %kv) (also not recommended) might be something like:

    c:\@Work\Perl\monks>perl -wMstrict -le "my %hash = (4 => 12, 34 => 102); ;; while (my @kv = each %hash) { local $, = ' => '; print @kv; } " 4 => 12 34 => 102
    (Update: In adding this Update, I screwed up the previous BTW example code. Everything's fixed now.)


    Give a man a fish:  <%-{-{-{-<

Re: Output of hash
by johngg (Canon) on Apr 23, 2019 at 21:27 UTC

    You are using arrays @k and @v so both key and value go into @k and @v gets nothing. Use scalars $k and $v instead.

    Cheers,

    JohnGG

Re: Output of hash
by Marshall (Canon) on Apr 23, 2019 at 23:39 UTC
    Perl has a kind of dichotomy between arrays and hashes. If you assign an array to a hash, the [0,2,4...] elements become the keys and the [1,3,5..] elements become the values (shown below).

    I think how to use each %hash has been well covered. However, I point out that iterating of the keys %hash is far, far more common. Usually what is desired is some kind of ordering of the printout, typically some kind of sorted order. (also shown below).

    Update: added another test case to show that both the key and the value windup in @k in this situation while ( my(@k, $v, $anything) = each %hash)

    Also worthy of note is that the order of the hash will vary between runs using recent Perl's. Run my code a couple of times and you will see. The function that calculates the internal binary hash key has a per run "fudge factor" - there are some security and other performance issues related to this behaviour. Bottom Line: Do not count on the each %hash function processing in the same order each run because it will not! This is one reason why using some kind of sort function upon keys is much,much more common (at least in my code) than using the each %hash function.

    #!/usr/bin/perl use strict; use warnings; my %hash = qw ( 6 18 50 150 3 9 7 21 91 273 9 27 1 3 4 12 34 102 89 267 76 228 ); foreach my $key (sort {$a <=> $b} keys %hash) #numeric sort (not defau +lt alpha sort) { print "$key=>$hash{$key}\n"; } print "\n"; my @keys = keys %hash; my @values = values %hash; print "below keys and values \"line up\" but not sure that is guarante +ed:\n"; printf "%3i ",$_ foreach @keys; print "\n"; printf "%3i ",$_ foreach @values; print "\n\n"; #show that both the key and the value will wind #up in @k in this situation.. while ( my(@k, $v, $anything) = each %hash) { print "\$v is undefined: \@k is: " if !defined $v; printf "%3i ",$_ for @k; print "\n"; } __END__ 1=>3 3=>9 4=>12 6=>18 7=>21 9=>27 34=>102 50=>150 76=>228 89=>267 91=>273 below keys and values "line up" but not sure that is guaranteed: 9 4 76 50 6 89 3 1 34 91 7 27 12 228 150 18 267 9 3 102 273 21 $v is undefined: @k is: 9 27 $v is undefined: @k is: 4 12 $v is undefined: @k is: 76 228 $v is undefined: @k is: 50 150 $v is undefined: @k is: 6 18 $v is undefined: @k is: 89 267 $v is undefined: @k is: 3 9 $v is undefined: @k is: 1 3 $v is undefined: @k is: 34 102 $v is undefined: @k is: 91 273 $v is undefined: @k is: 7 21
      below keys and values "line up" but not sure that is guaranteed:

      I'm not sure just what that statement refers to, but the following identical language from keys/values/each may be pertinent:

      So long as a given hash is unmodified you may rely on keys, values and each to repeatedly return the same order as each other. See Algorithmic Complexity Attacks in perlsec for details on why hash order is randomized. [emphases added]


      Give a man a fish:  <%-{-{-{-<

        Thanks for the link++. I was aware that the seed value had been randomized so that the binary hash value would therefore be randomized, but I didn't know any details about "Hash Traversal Randomization". Evidently when a collision occurs, lengthening the hash bucket's list, can cause/most likely will cause a significant difference in the order that bucket's list is returned when traversed *even if the number of hash buckets did not increase*. I wasn't sure if that order was "stable", but evidently it is as long as the hash is not modified. Of course all of this implies that if a deletion occurs, that can also change the order of presentation (which was not true before 5.18).

        values "line up" just means that key=>value correspondence between the horizontal presentation using values and keys vs the vertical presentation using each are the same.

        Update:
        I'll make some comments about Perl hash performance upon hash insert. A long time ago, I was working with what I thought were "big" hashes, 100-200K keys. An initial Perl hash array starts as a C array of pointers to lists, where the array size is 8. As the hash grows due to inserts, according to an algorithm, Perl's C array of pointers to lists (the number of hash "buckets") will double in size when Perl figures that is "the right thing to do"... 8,16,32,64,128,256,512,1024,2048... There is a lot of calculating that happens when the number of hash buckets doubles. There is a way to start out a Perl hash with a specified number of "buckets". I found out via a lot of benchmarking that didn't matter much. The C code that doubles the number of hash buckets runs very efficiently compared to my user Perl code that uses the hash. My conclusion is that Perl hashes work very, very well.

      Do not count on the each %hash function processing in the same order each run because it will not!

      And likewise keys and values and the list-context expansion of a hash.


      Give a man a fish:  <%-{-{-{-<

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-25 23:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found