对多级Perl哈希进行排序(动态地基于算术)

时间:2013-06-19 16:22:28

标签: perl sorting hash printing

如何根据键值对多级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))

5 个答案:

答案 0 :(得分:3)

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

宇宙飞船运营商在数字上将左侧与右侧进行比较。它最常见于最简单的情况,

$a <=> $b

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

答案 1 :(得分:3)

获取散列中所有值的列表:

values %hash;

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

map $_->{k2}, @list

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

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

按数字排序列表:

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

连接点:

sort { $a <=> $b } map { $_->{k2} // () } values %hash;

答案 2 :(得分:1)

print join ",", sort { $a <=> $b } map { $_->{k2} } values %hash;

答案 3 :(得分: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

答案 4 :(得分:-1)

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

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

请记住,$a$b是排序随机分配的哈希键。您不知道将哪个密钥分配给$a或将哪个密钥分配给$b。一次$a = "k1",另一次$b = "k1"。你甚至不知道比较的次数。您所知道的是,$a$b被分配给哈希中的键值,您的工作就是比较这两个键以获得您想要的结果。

这不起作用:

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

因为$a$b将被分配值k1k2k3。您的%property哈希中没有这些密钥。你可能会得到一堆警告。

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

例如,您不想在k2上进行排序,而是要对哈希值中所有值的总和进行排序。那是$hash{a}->{k1} + $hash{a}->{k2} + $hash->{k3}...$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;
}