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

Imagine the case when an array holding key/value pairs is assigned to an hash (i.e. normal hash initialization). What exactly happens when the key gets repeated, i.e. is twice or more times inside the array (on odd positions of course)? Of course this is like assigning this hash key twice, e.g. the second assignment simple overwrites the first.
my @array = ( 'A', 1, 'B', 2, 'C', 3, 'A', 4 ); my %hash = @array; # $hash{A} == 4 or 1 or depends??
Now my actual question: Is this a defined, stable thing, e.g. always the last key in the array would win? Or is it - for any reason - the first? Is it not explicitly defined and depends on something like the internal hash structure, e.g. the exact key names?

I came to this question when I had code where I have to add certain key/value pairs to an existing hash and want to make sure that already existing keys are overwritten:

%hash = (%hash,@array); # or %hash = (%hash,%otherhash);
of course I could just take a loop for this but I like the simplicity of this line and because the existing hash isn't very big the reassigning to itself is not very expensive. Now I would like to know if this really works like I think it does.

Replies are listed 'Best First'.
Re: Assigning list with duplicate keys to hash
by Fletch (Bishop) on Apr 22, 2008 at 16:04 UTC

    This comes up periodically (and I can't find the last thread I recall where it did), but I'm pretty sure the answer's always "While it's not explicitly spelled out verbatim that hashes are initialized from a LIST of key/value pairs in the order they occur in the list (so the value for the last instance of a given key 'wins'), that's the way Perl has worked for ages and this behavior is tangentially referenced in perldata so don't worry about using it." (The last paragraph under "List Value Constructors" says "Note that just because a hash is initialized in that order doesn't mean that it comes out in that order.")

    Update: Knew I'd find it after I'd already posted: Bulk hash population order

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thank you very much for the link. The included reference to the Perl Best Practices book which shows this as "recommended" way to do default values helped me a lot. I also liked the idea to use hash slices for this.
Re: Assigning list with duplicate keys to hash
by kyle (Abbot) on Apr 22, 2008 at 15:04 UTC

    In Perl Best Practices, TheDamian recommends using a hash for default parameters like so:

    my %DEFAULTS = ( a => 1, b => 2 ); sub foo { my $arg_ref = shift; my %args = ref $arg_ref eq ref {} ? ( %DEFAULTS, %{$arg_ref} ) : %DEFAULTS; }

    He clearly expects the second hash to overwrite the duplicated contents of the first, so I think it's safe to say this is defined behavior that you can rely on.

      In his OOP book he gives a much clearer, to me, way to do (almost) the same thing. I use it often. Dovetails nicely with Params::Validate.

      sub bar { my %args = ( mi => "default", mo => "default", mu => "default", @_ # list of args in key/val pairs ); # ... }
Re: Assigning list with duplicate keys to hash
by apl (Monsignor) on Apr 22, 2008 at 15:08 UTC
    Caveat: I don't know anything about Perl internals.

    Having said that, for the love of Groucho Marx, please don't write code that someone else may have to support because you like the simplicity of this line. I can't find anything in the documentation that says the conversion is required to work the way it does in the test of dwm042.

    Somewhere down the line, an internal change to Perl may result in the first occurrence being used, and the person supporting your code is going to wonder why the program no longer works.

    So, please, on behalf of the guiy who may have to do maintenance later on: be explicit in adding new keys to your hash.

    (Yeah, I'm being a little old lady. I'm a maintenance programmer. 8-) )

Re: Assigning list with duplicate keys to hash
by dwm042 (Priest) on Apr 22, 2008 at 14:52 UTC
    I don't claim to know anything about the guts of Perl, but in an assignment from an array to a hash, how the hash stores key value pairs should be immaterial. What is material is how Perl scans the array for elements and whether those elements are stored in the array in deterministic ashion. As far as I can tell, they are.

    Testing, I get:

    #!/usr/bin/perl use warnings; use strict; my @array = ( 'A', 1, 'B', 2, 'C', 3, 'A', 4 ); my %hash = @array; for (sort keys %hash ) { print "$_ => $hash{$_}\n"; } print "\n";
    And the output is (for Active State Perl 5.8.8):

    C:\Code>perl array-hash-order.pl A => 4 B => 2 C => 3
      What is material is how Perl scans the array for elements and whether those elements are stored in the array in deterministic ashion. As far as I can tell, they are.
      Yes, I came to the same conclusion. It makes sense that Perl is just reading the array elements and assigns the pairs to the hash. That would be deterministic. The thing is just to really be sure that this is always the case. Highly probably it is but I just wanted to seek the wisdom of other monks.
      Hi I have a same requirement to append the values of duplicate keys, like A => 1,4 in the above example. can anyone please help me?