in reply to Output of hash

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

Replies are listed 'Best First'.
Re^2: Output of hash
by AnomalousMonk (Archbishop) on Apr 24, 2019 at 03:26 UTC
    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.

Re^2: Output of hash
by AnomalousMonk (Archbishop) on Apr 24, 2019 at 03:01 UTC
    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:  <%-{-{-{-<