【问题标题】:Perl sort hash of hashes by the third-level key and compare itPerl 按三级键对散列进行排序并进行比较
【发布时间】:2018-03-03 08:10:06
【问题描述】:

我的数据结构是

my %hash = (
    firstkey  => { 
                secondkey => {
                            2 => ['9','2'],
                            1 => ['3','4'],
                            3 => ['8','2']
                }
            }
);

print Dumper \%hash;

我想按第三个键对哈希进行排序。即123 在这种情况下 然后比较数组中的第二个元素(index[1])。如果相同,则打印出来。

预期的排序哈希:

my %hash = (
    firstkey  => { 
                secondkey => {
                            1 => ['3','4'],
                            2 => ['9','2'],
                            3 => ['8','2']
                }
            }
);

print Dumper \%hash;

对哈希排序后,我们将第一个数组[3,4]index[1] 与第二个数组[9,2] 进行比较。 4 不等于 2,所以我们不会打印任何东西。

然后,我们将第二个数组[9,2]index[1] 与第三个数组[4,2] 进行比较。 2等于2,那么我们就打印它的所有内容

firstkey, secondkey, 3, [8,2]

我们只需要比较相邻的数组。

我阅读了很多关于排序哈希的解决方案,但我找不到真正重新排序它的解决方案有没有办法通过键重新排序哈希并在 Perl 中使用新顺序构造哈希? 还是只能通过for循环对hash进行排序,在for循环中进行比较?

【问题讨论】:

  • 你不能“sort hash”——它们本质上是无序的。但是你可以得到一个排序的键列表,在散列键列表上使用sort 和你想要的任何标准。然后,您有一个 ordered 键列表进行迭代,因此您可以以“排序方式”使用您的散列。请参阅this post 以对类似的哈希进行排序,或this post 以使用一些 cmets 进行更复杂的排序。还有更多。
  • @zdim 感谢您的建议。我正在尝试。
  • 虽然上述评论总体上很好并且需要,并且值得关注,但它可能无助于解决这个问题(因此可能会产生误导)——我发布了一个答案。

标签: arrays perl sorting hash


【解决方案1】:

不能有“排序哈希”——它们本质上是无序的数据结构(参见keys)。初始种子和哈希遍历的随机化甚至是enhanced for security purposes

但是我们可以根据需要对哈希键列表进行排序。然后我们有一个有序列表进行迭代,因此可以以“排序方式”处理哈希。

此处排序的键位于更深的级别,因此请遍历上(两个)级别以找到它们。然后就是简单的排序和测试

use warnings;
use strict;
use feature 'say';

my %hash = ( 
    firstkey1 => { 
        secondkey1 => { 
            2 => [9, 2], 1 => [3, 4], 3 => [8, 2]  
        }   
    }   
);

foreach my $k1 (keys %hash) 
{
    foreach my $k2 (keys %{$hash{$k1}}) 
    {   
        # Relieve syntax below
        my $hr = $hash{$k1}{$k2};

        my @sr_k3 = sort { $a <=> $b } keys %{$hr};

        foreach my $i (1..$#sr_k3)
        {
            if ( $hr->{$sr_k3[$i]}[1] == $hr->{$sr_k3[$i-1]}[1] )
            {
                say "$k1, $k2, $sr_k3[$i], ", 
                    '[', join(',', @{$hr->{$sr_k3[$i]}}), ']';
            }
        }   
        #say "@{$hash{$k1}{$k2}{$_}}" for keys %{$hash{$k1}{$k2}};
    }   
}

一些笔记

  • 由于比较标准,排序的键被迭代从第二个开始

  • Hashref 被复制到第二层只是为了方便,以减轻混乱的语法

  • 当复杂的数据结构变得过于笨拙时,可能是时候改用类了

这适用于两个级别中的任意数量的键(每个级别仅显示一个键)。

【讨论】:

  • 非常简单直接的解决方案。感谢您的帮助
【解决方案2】:

如前所述,您将无法指定散列的顺序。这是一种将其映射到您可以排序并进行所需比较的方法。

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my %hash = ( firstkey => {
                secondkey => {
                    2 => [9,2],
                    1 => [3,4],
                    3 => [8,2],
                }
            }
        );


#obtain an array of two-element array refs, whose contents are the keys
#for the "secondkey" hash and the corresponding value, respectively

my @arr = map { [ $_, $hash{firstkey}->{secondkey}->{$_} ] }
          keys %{$hash{firstkey}->{secondkey}};

#sort on the aforementioned key

my @sorted = sort { $a->[0] <=> $b->[0] } @arr;

#obtain an array of array refs, whose contents are a pair of adjacent 
#elements from the @sorted array

my @ordered_pairs = map { [ $sorted[$_], $sorted[$_+1] ] }
                    (0 .. (scalar @sorted - 2));

#compare the elements in question, and do something if there's a match

for (@ordered_pairs) {
    if ($_->[0][1][1] == $_->[1][1][1]) {
        print Dumper $_->[1];
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 2014-05-07
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    相关资源
    最近更新 更多