【问题标题】:Sorting multi-level Perl hash (dynamically based on arithmetic)对多级 Perl 哈希进行排序(基于算术动态)
【发布时间】:2013-06-16 06:59:42
【问题描述】:

如何根据键值对多级 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{key}{k2} * $property{key} 的数值对%hash 进行排序吗? 使用

#!/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))

【问题讨论】:

  • 您是要按第一级键(a, b, c)的字母顺序对k2 值(52, 62, 72)进行排序,还是要按数字对所有k2 值进行排序?跨度>
  • 添加了一个额外的问题
  • @Jean 这是一个全新的(尽管相关性松散)的问题。因此,ask a new one.

标签: perl sorting hash printing


【解决方案1】:

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

values %hash;

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

map $_->{k2}, @list

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

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

对列表进行数字排序:

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

连接点:

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

【讨论】:

  • @mpapec 不,你提到了join,我忘记了。我们的答案是互补的
【解决方案2】:
sort {$hash{$a}{'k2'} <=> $hash{$b}{'k2'}} keys %hash

宇宙飞船运算符将左侧与右侧进行数值比较。它最常见于最简单的情况,带有

$a <=> $b

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

【讨论】:

  • 我会选择特殊的-&gt; 运算符:sort $hash{$a}-&gt;{k2} &lt;=&gt; $hash{$b}-&gt;{k2} keys %hash;。它更容易阅读——尤其是当 OP 将向哈希添加另一个哈希时。
【解决方案3】:

这个程序按你的要求做。它首先列出按值排序的k2 元素的值,然后列出按其乘积排序的相同元素与%property 哈希的对应元素。

请注意,52,72,62 的预期输出是错误的。正如您所说,产品是a =&gt; 364, b =&gt; 372, c =&gt; 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

【讨论】:

  • sort { $hash{$b}{k2}*$propery{$b} &lt;=&gt; $hash{$a}{k2}*$property{$a} } keys %hash 似乎可行..这种方法有什么陷阱吗?
  • @Jean:没有,只是它违反了DRY (Don't Repeat Yourself) 开发原则。如果您手动复制任何内容,则副本有可能与原始内容不一致。您的评论就是一个很好的例子!
  • 我不清楚这里复制了什么? $a/$b ?
  • @Jean:表达式$hash{$_}{k2}*$property{$_}
【解决方案4】:
print join ",", sort { $a <=> $b } map { $_->{k2} } values %hash;

【讨论】:

    【解决方案5】:

    使用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}-&gt;{k1} + $hash{a}-&gt;{k2} + $hash-&gt;{k3}...$hash{c}-&gt;{k1} + $hash{c}-&gt;{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;
    }
    

    【讨论】:

    • ysth 没有发布答案。你的意思是YatesCM?如果是这样,那么您所做的就是添加不必要的 -&gt; 间接运算符,我认为这很嘈杂且 less 清晰。另外,您说%hash 的键是k1 ..k3,而实际上它们是a ..c:与%property 的键相同,所以您说的排序语句不会工作绝对没问题。
    猜你喜欢
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    相关资源
    最近更新 更多