For a hash of this format:
my $itemHash = {
tag1 => {
name => "Item 1",
order => 1,
enabled => 1,
},
tag2 => {
name => "Item 2",
order => 2,
enabled => 0,
},
tag3 => {
name => "Item 3",
order => 3,
enabled => 1,
},
...
}
I have this code that correctly iterates through the hash:
keys %$itemHash; # Resets the iterator
while(my($tag, $item) = each %$itemHash) {
print "$tag is $item->{'name'}"
}
However, the order that these items are iterated in seems to be pretty random. Is it possible to use the same while
format to iterate through them in the order specified by the 'order' key in the hash for each item?
(I know I can sort the keys first and then foreach loop through it. Just looking to see if there is cleaner way to do this.)
You can do some thing like :
foreach my $key (sort keys %{$itemHash}) {
print "$key : " . $itemHash->{$key}{name} . "\n";
}
The concept of an "ordered hash" is wrong. While an array is an ordered list of elements, and therefore accessible by index, a hash is an (un-ordered) collection of key-value pairs, where the keys are a set.
To accomplish your task, you would have to sort the keys by the order
property:
my @sorted = sort {$hash{$a}{order} <=> $hash{$b}{order}} keys %$itemHash;
You can then create the key-value pairs via map
:
my @sortedpairs = map {$_ => $itemHash->{$_}} @sorted;
We could wrap this up into a sub:
sub ridiculousEach {
my %hash = @_;
return map
{$_ => $hash{$_}}
sort
{$hash{$a}{order} <=> $hash{$b}{order}}
keys %hash;
}
to get an even-sized list of key-value elements, and
sub giveIterator {
my %hash = @_;
my @sorted = sort {$hash{$a}{order} <=> $hash{$b}{order}} keys %hash;
return sub {
my $key = shift @sorted;
return ($key => $hash{$key});
};
}
to create a callback that is a drop-in for the each.
We can then do:
my $iterator = giveIterator(%$itemHash);
while (my ($tag, $item) = $iterator->()) {
...;
}
There is a severe drawback to this approach: each
only uses two elements at a time, and thus operates in constant memory. This solution has to read in the whole hash and store an array of all keys. Unnoticable with small hashes, this can get important with a very large amount of elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With