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

I was surprised to see that a hash tied with Tie::IxHash loses the ordering when processed in a sub:
use strict; use warnings; use Tie::IxHash; tie my %h, 'Tie::IxHash', (a => 1, b => 2, c => 3); warn $_ for keys %h; # prints in assigned order sub printh { my %x=@_; warn $_ for keys %x; # prints in scattered order! } printh(%h);
Is there anyway to preserve ordering when passing it? I suppose the OO way of making a tied hash would do, but I prefer normal Perl hashes over the OO interface.

Replies are listed 'Best First'.
Re: having a hash maintain order when passed to a sub
by JavaFan (Canon) on May 14, 2009 at 15:33 UTC
    You are not passing a hash to the sub. You flatten the hash to a list, pass that list, and build a new hash in the sub.

    Either make the new hash also a tied hash, or pass a reference to the hash. The latter is more efficient, but if you change the hash inside the sub, the outer hash (which is the same) is changed as well.

Re: having a hash maintain order when passed to a sub
by ikegami (Patriarch) on May 14, 2009 at 16:02 UTC
    The only thing that can be passed to a sub is a list of scalars. You did not pass a hash to the sub, and the new hash you created in the sub isn't an IxHash. Solutions:
    sub printh { tie my %x, 'Tie::IxHash', @_; # Recreate the hash. Expensive warn $_ for keys %x; } printh(%h); # Flatten the hash
    sub printh { my ($x) = @_; warn $_ for keys %$x; } printh(\%h); # Pass a reference
Re: having a hash maintain order when passed to a sub
by Your Mother (Archbishop) on May 14, 2009 at 15:33 UTC

    I haven't tried but I expect passing it as a reference instead of letting it be flattened out into a list and copied into a new hash should do.