【问题标题】:How can I sort a Perl array of array of hashes?如何对哈希数组的 Perl 数组进行排序?
【发布时间】:2010-03-24 18:16:47
【问题描述】:
@aoaoh;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}

输出是:

22=31 21=31 23=17

但我希望它是

21=31 22=31 23=17

请告诉我哪里错了。

另外我如何对值进行排序以便我得到输出

23=17 22=31 21=31(如果 2 个键的值相同,则值较高的键先出现)

【问题讨论】:

  • use strict; - 请!

标签: arrays perl sorting hash perl-data-structures


【解决方案1】:

听起来像你想要的:

for $val (sort keys %{$aoaoh[$i][$k]}) {

和:

for $val (reverse sort keys %{$aoaoh[$i][$k]}) {

虽然从您的评论看来您不想要纯粹的反向排序。你想创建自己的排序函数:

for $val (sort {$aoaoh[$i][$k]->{$a} <=> $aoaoh[$i][$k]->{$b} || $a <=> $b} keys %{$aoaoh[$i][$k]}) {

【讨论】:

  • 我认为他问题的后半部分是如何按值排序,而不是按键排序。只是巧合,这与反向键顺序相同。
  • 是的..会得到我..我想对值进行排序,然后如果有 2 个值,则按降序对这 2 个进行排序...
  • 你能告诉我怎么做吗?
  • 是的,在我的回答中放一个示例排序函数。
  • 嘿..我还有一个疑问..我们可以不使用for循环对@aoaoh进行排序..在我不打印它们而只想按排序顺序保存它的情况下..做我需要使用循环吗?
【解决方案2】:

听起来您希望哈希按照定义的顺序返回它们的键和值,而 perl 中没有这样的保证。

您可以实现一个更复杂的数据结构来为您处理一些排序,或者在您的显示中添加一些排序逻辑(而不仅仅是循环),或者加载一个模块来支持有序哈希,例如 @ 987654321@.

我希望 Tie::Hash::Indexed 实现看起来像这样:

my @aoaoh;

use Tie::Hash::Indexed;
tie my %hash, 'Tie::Hash::Indexed';
$aoaoh[0][0] = \%hash;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}

【讨论】:

  • 我有一个哈希数组。我希望内部数组中的哈希首先按它们的值排序,当值相同时,按它们的键反向排序..
  • for $val (排序 {$aoaoh[$i][$k]->{$a} $aoaoh[$i][$k]->{$b} | | $b $a} keys %{$aoaoh[$i][$k]}) Epsilon 的解决方案..这就是我想要的..但​​我想避免循环所以什么是替代方案。 ..
【解决方案3】:

我回答了这个用户的另外两个完全相同的问题,但看起来这个会赢,所以我也在这里回答。

perlfaq4 回复How do I sort an array by anything


为 sort() 提供一个比较函数(在 perlfunc 中的 sort 中描述):

@list = sort { $a <=> $b } @list;

默认排序函数是 cmp,字符串比较,它将 (1, 2, 10) 排序为 (1, 10, 2)。上面使用的 是数值比较运算符。

如果你有一个复杂的函数需要取出你想要排序的部分,那么不要在排序函数中执行它。先把它拉出来,因为同一个元素可以多次调用sort BLOCK。这是一个示例,说明如何提取每个项目的第一个数字之后的第一个单词,然后不区分大小写对这些单词进行排序。

@idx = ();
for (@data) {
    ($item) = /\d+\s*(\S+)/;
    push @idx, uc($item);
    }
@sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];

也可以这样写,使用一种被称为 Schwartzian 变换的技巧:

@sorted = map  { $_->[0] }
    sort { $a->[1] cmp $b->[1] }
    map  { [ $_, uc( (/\d+\s*(\S+)/)[0]) ] } @data;

如果您需要对多个字段进行排序,以下范例很有用。

@sorted = sort {
    field1($a) <=> field1($b) ||
    field2($a) cmp field2($b) ||
    field3($a) cmp field3($b)
    } @data;

这可以方便地与上面给出的密钥的预先计算相结合。

有关此方法的更多信息,请参阅http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz 中“远远超出您想知道的范围”集合中的分类文章。

另请参阅 perlfaq4 后面关于排序哈希的问题。

【讨论】:

    【解决方案4】:

    第一季度的答案是:

    print "${$aoaoh[0][0]}{$_}=$_\n" for sort keys %{$aoaoh[0][0]};
    

    可以写成:

    for (sort keys %{$aoaoh[0][0]}) {
        print "${$aoaoh[0][0]}{$_}=$_\n"
    }
    

    Q2 的答案:

    print "$_->[1]=$_->[0]\n" for
    map { [$_->[0], $_->[1]] }
    sort { $a->[0] cmp $b->[0] }
    map { [ ${$aoaoh[0][0]}{$_}, $_ ] } keys %{$aoaoh[0][0]};
    

    【讨论】:

      猜你喜欢
      • 2012-01-21
      • 1970-01-01
      • 2019-04-25
      • 2010-10-24
      • 1970-01-01
      • 2011-03-10
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      相关资源
      最近更新 更多