对于这种格式的哈希:
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,
},
...
}
我有这个代码正确地遍历哈希:
keys %$itemHash; # Resets the iterator
while(my($tag, $item) = each %$itemHash) {
print "$tag is $item->{'name'}"
}
然而,迭代这些项的顺序似乎很随机。是否可以使用相同的while
格式按照每个项目的哈希中“order”键指定的顺序迭代它们?
(我知道我可以先对键进行排序然后再循环遍历它。只是想看看是否有更简洁的方法来执行此操作。)
答案 0 :(得分:8)
“有序哈希”的概念是错误的。虽然数组是元素的有序列表,因此可以通过索引访问,但哈希是键值对的(无序)集合,其中键是一组。
要完成任务,您必须按order
属性对键进行排序:
my @sorted = sort {$hash{$a}{order} <=> $hash{$b}{order}} keys %$itemHash;
然后,您可以通过map
:
my @sortedpairs = map {$_ => $itemHash->{$_}} @sorted;
我们可以把它包装成一个子:
sub ridiculousEach {
my %hash = @_;
return map
{$_ => $hash{$_}}
sort
{$hash{$a}{order} <=> $hash{$b}{order}}
keys %hash;
}
获取一个大小合适的键值元素列表,
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});
};
}
创建一个回调函数,该回调函数是每个回调函数。
我们可以这样做:
my $iterator = giveIterator(%$itemHash);
while (my ($tag, $item) = $iterator->()) {
...;
}
这种方法有一个严重的缺点:each
一次只使用两个元素,因此在恒定的内存中运行。此解决方案必须读取整个哈希并存储所有键的数组。对于小哈希来说不明显,这对于大量元素来说非常重要。
答案 1 :(得分:6)
你可以做一些事情:
foreach my $key (sort keys %{$itemHash}) {
print "$key : " . $itemHash->{$key}{name} . "\n";
}
答案 2 :(得分:5)
散列中的键未定义的顺序。所以你需要对键进行排序。正如你所说,一种方法是拉出钥匙并对它们进行分类,然后循环通过钥匙。
另一种方法是动态排序。我不确定你会认为它更干净。类似的东西:
for my $key ( sort { $itemHash->{$a}{order} <=> $itemhash->{$b}{order} } keys %$itemHash ) {
print "$key is $itemHash->{$key}{name}";
}
答案 3 :(得分:2)
这将更加清洁。我们必须使用cmp来排序字符串。
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, } }; foreach((sort{$a cmp $b}(keys(%$itemHash)))){ print "$_ is $itemHash->{$_}->{'name'}\n"; }