Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I retain insertion order of a nested Perl hash?

Tags:

perl

I can use IxHash to remember the insertion order of a hash.

use Tie::IxHash;

my %hash;
tie(%hash, 'Tie::IxHash');
%hash = (
  x => 10,
  z => 20,
  q => { a1 => 1, a3 => 5, a2=>2,},
  y => 30,
);

printf("keys %s\n", join(" ", keys %hash));

=> keys x z q y

How about the nested hash?

printf("keys %s\n", join(" ", keys %{$hash{q}}));
keys a2 a1 a3

I suspect the answer is no as the q hash is anonymous and the order is lost before IxHash sees it.

I know that I can do Tie on $hash{q} and then add the elements, but I like using the single assignment to build the hash.

Is there a trick?

like image 862
mmccoo Avatar asked Jun 08 '10 21:06

mmccoo


1 Answers

There are multiple ways to do this, I would just wrap up the tie in a subroutine so that its easy to use inline:

use Tie::IxHash;

sub ordered_hash (%) {
    tie my %hash => 'Tie::IxHash';
    %hash = @_;
    \%hash
}

and then:

tie my %hash => 'Tie::IxHash';

%hash = (
    x => 10,
    z => 20,
    q => ordered_hash( a1 => 1, a3 => 5, a2=>2 ),
    y => 30,
);

the (%) prototype on the subroutine tells perl that it takes a list with an even number of elements

like image 193
Eric Strom Avatar answered Nov 08 '22 00:11

Eric Strom