在数组的哈希或哈希的哈希中按哈希值对Perl进行排序

3

请问我在这里做错了什么?我尝试了几乎所有可能的数组/哈希类型和排序查询组合,但似乎无法使其工作。

我正在尝试按 value1 对下面的哈希引用进行排序:

my $test = {
    '1' => { 'value1' => '0.001000', 'value2' => 'red'},
    '2' => { 'value1' => '0.005000', 'value2' => 'blue'},
    '3' => { 'value1' => '0.002000', 'value2' => 'green'},
    '7' => { 'value1' => '0.002243', 'value2' => 'violet'},
    '9' => { 'value1' => '0.001005', 'value2' => 'yellow'},
    '20' => { 'value1' => '0.0010200', 'value2' => 'purple'}
};

使用这个排序循环:
foreach (sort { $test{$a}->{'value1'} <=> $test{$b}->{'value1'} } keys \%{$test} ){
    print "key: $_ value: $test->{$_}->{'value1'}\n"
}

I get:

key: 1 value: 0.001000
key: 3 value: 0.002000
key: 7 value: 0.002243
key: 9 value: 0.001005
key: 2 value: 0.005000
key: 20 value: 0.0010200

我已经尝试过使用整数,但似乎出现了相同的问题。
实际上,我并不需要遍历哈希表,我只是想为以后的使用进行排序。使用哈希数组很容易实现,但对于哈希表嵌套的情况则不然。

3
您说“实际上我并不需要遍历哈希表,只是想在以后使用时它有序一些。”但是您无法对哈希表进行排序。您可以按特定顺序迭代键,但哈希表本身不会被排序。 - ThisSuitIsBlackNot
谢谢!那正是我最终想要的答案。回到数组上吧...我认为一次排序数组比每次需要使用时都要排序哈希表更快,而在我的当前情况下,每秒需要使用很多次(我猜你可以在遍历键时创建一个新的哈希表)。 - someuser
你不能对哈希进行排序。你可以将键的排序列表存储在数组中,并使用它来设置你用于迭代哈希的顺序,但这仅适用于您不添加或删除哈希元素的情况。my @sorted = sort keys %hash; for (@sorted) { ... } - ThisSuitIsBlackNot
4个回答

6
不要在引用上调用键,应该在实际的哈希表上调用。此外,这个$test{$a}->应该改为$test->{$a},因为$test是一个哈希表引用。
foreach (sort { $test->{$a}{'value1'} <=> $test->{$b}{'value1'} } keys %{$test} ){
    print "key: $_ value: $test->{$_}->{'value1'}\n"
}

如果你已经开启了 use strict;use warnings;,你就会收到以下错误提示,以便提醒你存在的问题:
Global symbol "%test" requires explicit package name

谢谢。我本来以为我试过了,但我想我是在尝试使用我的%test =(...); - someuser
1
启用警告将会指出比较的值是未定义的。 - ysth

3
我想提供其他答案的来源和一个可行的代码示例。正如他们所说,您正在使用哈希引用调用keys。根据文档

从Perl 5.14开始,keys可以使用标量EXPR,其中必须包含对未装箱的哈希或数组的引用。参数将自动取消引用。这个keys的方面被认为是高度实验性的。确切的行为可能会在将来的Perl版本中更改。

for (keys $hashref) { ... }
for (keys $obj->get_arrayref) { ... }

然而,这对我有效:
#!/usr/bin/perl
use strict;
use warnings;

my $test = {
    '1' => { 'value1' => '0.001000', 'value2' => 'red'},
    '2' => { 'value1' => '0.005000', 'value2' => 'blue'},
    '3' => { 'value1' => '0.002000', 'value2' => 'green'},
    '7' => { 'value1' => '0.002243', 'value2' => 'violet'},
    '9' => { 'value1' => '0.001005', 'value2' => 'yellow'},
    '20' => { 'value1' => '0.0010200', 'value2' => 'purple'}
};


foreach (sort { $test->{$a}->{'value1'} <=> $test->{$b}->{'value1'} } keys \%{$test} ) {
    print "key: $_ value: $test->{$_}->{'value1'}\n"
}

例子:

matt@mattpc:~/Documents/test/10$ perl test.pl 
key: 1 value: 0.001000
key: 9 value: 0.001005
key: 20 value: 0.0010200
key: 3 value: 0.002000
key: 7 value: 0.002243
key: 2 value: 0.005000
matt@mattpc:~/Documents/test/10$ perl --version
This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi
(with 88 registered patches, see perl -V for more detail)

使用哈希引用作为 keys 的输入是我不推荐的。

我建议按照其他问题的建议添加 use strictuse warnings 并将哈希引用更改为哈希 %{test}


2

这是简单的keys %$testkeys 的参数必须是哈希表,而不是哈希表引用。 \%${test}$test 是相同的,都是引用。

使用 $test->{$a},而不是 $test{$a},因为 $test 是哈希表引用,而不是哈希表。

foreach (sort { $test->{$a}->{'value1'} <=> $test->{$b}->'{value1'} } keys %$test) {
    print "key: $_ value: $test->{$_}->{'value1'}\n"
}

或者使用一些语法糖的缩写形式:您可以省略第一个箭头后面的额外箭头。而且在处理哈希时,您不必引用字符串文字键。
foreach (sort { $test->{$a}{value1} <=> $test->{$b}{value1} } keys %$test) {
    print "key: $_ value: $test->{$_}{value1}\n"
}

通常情况下,为了调试至少启用use warnings;会非常有帮助。


0
我能发现的唯一错误是使用哈希引用\%{$test},而应该使用哈希%$testkeys可以与之配合使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接