Do latter keys in an hash assignment from an array always override earlier keys?

Viewed 63

Given this:

%h = (a => 3, b => 4, a => 5);

Imperically $h{a} == 5 holds true, but are there cases where $h{a} == 3 because of internal dictionary hashing or some other perl-internal behavior?

Another way to ask: Does perl guarantee to keep key-ordering the same when assigning an array to a hash, even in the event of a key collision?

Duplicates key entries are convenient for things like %settings = (%defaults, %userflags) so I can hard-code defaults but override with user supplied flags.

2 Answers

Yes, you can rely that the assignment list will be evaluated left to right as surely as you could rely on an assignment to an array occurring in the correct order.

sub DebugHash::TIEHASH { bless {}, shift }
sub DebugHash::CLEAR { %{shift} = (); }
sub DebugHash::STORE {
    my ($tied, $key, $value) = @_;
    print STDERR "STORE '$key' => '$value'\n";
    $tied->{$key} = $value;
}

tie %hash, 'DebugHash';
%hash = (a => 'first', a => 'second', a => 'third',
         a => 'fourth', a => 'next', a => 'last');

Output:

STORE 'a' => 'first'
STORE 'a' => 'second'
STORE 'a' => 'third'
STORE 'a' => 'fourth'
STORE 'a' => 'next'
STORE 'a' => 'last'

key-ordering in a hash appears quite random. That is you cannot guarantee that the hash when dumped or looked at will be in the same order as you assigned it (a => 3, b => 4, a => 5); it could be displayed as ( b => 4, a => 5).

Also, there are only two key values in your hash the collision simply overwrites the first:

use Data::Dumper;

my %h = (a => 3, b => 4, a => 5);

print Dumper(\%h);
$VAR1 = {
          'a' => 5,
          'b' => 4
        };

It took me only three tries to produce:

$VAR1 = {
          'b' => 4,
          'a' => 5
        };

Updating as @mob mentioned left to right is what I would assume the second (or nth) assignment of a value to a key will replace the previous value. In this case you are replacing the whole hash the left to right ordering would result in a hash with two elements the value of any duplicates would be the last key/value encountered.

Related