2

如何根据键值对多级 perl 哈希进行排序(和打印)?

%hash = (
  a => { k1 => 51, k2 => 52, k3 => 53 },
  b => { k1 => 61, k2 => 62, k3 => 63 },
  c => { k1 => 71, k2 => 72, k3 => 73 },
)

例如,根据k2?的值对上述散列进行数字排序 所以它应该打印:

52,62,72

我想知道如何使用

sort { $hash{$b} <=> $hash{$a} } keys %hash`

编辑

如果我有另一个哈希

my %property = ( a => 7, b => 6, c => 5 )

我可以根据 使用%hash的数值 进行排序吗$hash{key}{k2} * $property{key}

#!/usr/bin/perl
use strict;
use warnings;

my %hash = (
  a => { k1 => 51, k2 => 52, k3 => 53 },
  b => { k1 => 61, k2 => 62, k3 => 63 },
  c => { k1 => 71, k2 => 72, k3 => 73 },
);

my %property = ( a => 7, b => 6, c => 5 );


foreach (sort { ($hash{$a}{'k2'}*$property{$a}) <=> 
                ($hash{$b}{'k2'}*$property{$b}) } keys %hash)
{
    printf("[%d][%d][%d]\n",
    $hash{$_}{'k2'},$property{$_},$hash{$_}{'k2'}*$property{$_});
}

结果应该是

72,52,62    as products are (360(72*5),364(52*7),372(62*6))
4

5 回答 5

3
sort {$hash{$a}{'k2'} <=> $hash{$b}{'k2'}} keys %hash

宇宙飞船操作员在数字上比较左侧和右侧。在最简单的情况下最常见的是

$a <=> $b

但在这种情况下,您想比较散列中的值,它也可以这样做。

于 2013-06-19T16:26:25.323 回答
3

获取哈希中所有值的列表:

values %hash;

将 hashrefs 列表转换为k2条目的内容:

map $_->{k2}, @list

哦,如果undef/ 不存在就跳过它:

map $_->{k2} // (), @list

对列表进行数字排序:

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

将点连接:

sort { $a <=> $b } map { $_->{k2} // () } values %hash;
于 2013-06-19T16:28:50.617 回答
1
print join ",", sort { $a <=> $b } map { $_->{k2} } values %hash;
于 2013-06-19T16:31:33.833 回答
1

该程序按您的要求执行。它首先列出按值k2排序的元素的值,然后列出按其乘积排序的相同元素与%property哈希的相应元素。

请注意,您的预期输出52,72,62是错误的。正如您所说,产品是,a => 364, b => 372, c => 360因此值应按顺序排序c, a, b72, 52, 62

use strict;
use warnings;

my %hash = (
  a => { k1 => 51, k2 => 52, k3 => 53 },
  b => { k1 => 61, k2 => 62, k3 => 63 },
  c => { k1 => 71, k2 => 72, k3 => 73 },
);

my %property = ( a => 7, b => 6, c => 5 );

print join ',', map { $hash{$_}{k2} } sort {
  my ($aa, $bb) = map { $hash{$_}{k2} } $a, $b;
  $aa <=> $bb;
} keys %hash;
print "\n";

print join ',', map { $hash{$_}{k2} } sort {
  my ($aa, $bb) = map { $hash{$_}{k2} * $property{$_} } $a, $b;
  $aa <=> $bb;
} keys %hash;
print "\n";

输出

52,62,72
72,52,62
于 2013-06-19T17:26:52.093 回答
-1

使用ysth 的答案,但这种语法可能会让事情更容易理解:

sort { $hash{$a}->{k2} <=> $hash{$b}->{k2} } keys %hash;

请记住,$aand$b是由排序随机分配的哈希键。您不知道分配给$a什么键或分配给什么键$b。一次$a = "k1"又一次$b = "k1"。您甚至不知道进行了多少次比较。您所知道的就是$a$b被分配给哈希中的键值,您的工作是比较这两个键以获得您想要的结果。

这是行不通的:

sort { $hash{$a}->{k2} * $property{$a} <=> $hash{$b}->{k2} * $property{$b} } keys %hash;

因为$a$b将被赋值为k1,k2k3%property您的哈希中没有这些键。你可能会收到一堆警告。

如果您的排序算法比简单的单列更复杂,您会怎么做?您可以指定一个子例程来为您进行排序。

例如,您希望对散列中所有值的总和进行排序,而不是对 k2 进行排序。那是$hash{a}->{k1} + $hash{a}->{k2} + $hash->{k3}...vs. $hash{c}->{k1} + $hash{c}->{k2}...,我不知道任何键是什么。此子例程将找到所有键%{ hash{$a} }并将它们相加并将它们与中的所有键进行比较%{ hash{$b} }

sort sort_function keys %hash;

sub sort_function {

    # Sum of all the values in the hash %{ $hash{$a} }
    my $sum_a = 0;
    for my $hash_key ( keys %$hash{$a} ) {
       $sum_a += $hash{$a}->{$hash_key};
    }
    # Sum of all the values in the hash %{ $hash{$b} }
    my $sum_b = 0;
    for my $hash_key ( keys %$hash{$b} ) {
       $sum_b += $hash{$b}->{$hash_key};
    }
    return $sum_a <=> $sum_b;
}
于 2013-06-19T19:18:04.907 回答