in reply to Re^2: delete duplicate hash value's
in thread delete duplicate hash value's
I don't think that Perl guarantees that behavior.
In general, hashes are iterated in bucket order, (and Perl does guarentee that values are returned in the same order as keys). Bucket order is a function of the hashing algorithm used which is fixed in Perl. Even with the hash randomisation fix for the "algorithm complexity attack" on Perl's hashes--which changes the initalisation values used by the hashing algorithm, the ordering is guarenteed to remain the same for any given run of the program which is all that is required of the code above.
Essentially, if a hash contains the same keys, keys (and therefore values) will return them in the same order, regardless of the order they were inserted in. This can be demonstrated to be so:
#! perl -sw use 5.010; use strict; use List::Util qw[ shuffle ]; our $I ||= 1e6; sub genHash { my %hash; @hash{ shuffle 'a'..'d' } = 1 .. 4; return \%hash; } my $datum = join ' ', keys %{ genHash() }; warn $datum . "\n"; for my $i ( 1 .. $I ) { my $test = join ' ', keys %{ genHash() }; die "test failed after $i iters: $datum vs. $test\n" unless $datum eq $test; } say "Test passed for $I iterations" __END__ C:\test>junk2 c a b d Test passed for 1000000 iterations
However, there is a caveat to this that obviously did not occur to me back in the day. Whilst the iteration order is independent of the insertion order, it is dependant upon the number of buckets in the hash.
That is, if the hashes being compared contain the same keys--and have never contained any other keys--their iteration orders will be the same. But, if the hashes have different numbers of buckets; if for example, one of them has previously contained more keys some of which have subsequently been deleted; then their iteration orderings will differ:
@hashA{ 'a'..'d' } = 1..4;; @hashB{ 'a'..'j' } = 1 .. 10;; delete $hashB{ $_ } for 'e' .. 'j';; print scalar %hashA;; 4/8 print scalar %hashB;; 4/16 print join ' ', keys %hashA;; c a b d print join ' ', keys %hashB;; a d c b
So, whilst this is unlikely to have affected the OPs application, for general application it would be better to sort the values by key order. As would using a join delimiter that is not going to occur in the values being concatenated:
my $value_key = join $;, @students{ sort keys %{ $students{ $key } } } +;
|
|---|