Perl,对嵌套哈希进行排序

时间:2018-07-10 04:55:39

标签: perl hash hashtable

我有一个看起来像这样的数据结构(散列):

$VAR1 = {
          'masterkeyB' => {
                'D' => ['b', 'c', 'a'],
                'A' => ['b', 'a', 'c'],
                'C' => ['a', 'c', 'b'],
                'B' => ['a', 'c', 'b'],
              },
          'masterkeyA' => {
                'B' => ['a', 'c', 'b'],
                'C' => ['a', 'c', 'b'],
                'A' => ['b', 'a', 'c'],
                'D' => ['b', 'c', 'a'],
                }
        };

我想按字母顺序对该结构进行排序:

$VAR1 = {
          'masterkeyA' => {
                'A' => ['a', 'b', 'c'],
                'B' => ['a', 'b', 'c'],
                'C' => ['a', 'c', 'b'],
                'D' => ['a', 'b', 'c'],
              },
          'masterkeyB' => {
                'A' => ['a', 'b', 'c'],
                'B' => ['a', 'b', 'c'],
                'C' => ['a', 'c', 'b'],
                'D' => ['a', 'b', 'c'],
                }
        };

请注意,除“ C”外,所有数组均已排序。

3 个答案:

答案 0 :(得分:1)

只需遍历嵌套循环中的键,对遇到的值进行排序。编辑:请参阅http://p3rl.org/dsc#HASHES-OF-HASHES

use feature qw(postderef);
use Tie::Hash::Indexed qw();

my $unsorted = {
    'masterkeyB' => {
        'D' => ['b', 'c', 'a'],
        'A' => ['b', 'a', 'c'],
        'C' => ['a', 'c', 'b'],
        'B' => ['a', 'c', 'b'],
    },
    'masterkeyA' => {
        'B' => ['a', 'c', 'b'],
        'C' => ['a', 'c', 'b'],
        'A' => ['b', 'a', 'c'],
        'D' => ['b', 'c', 'a'],
    }
};

tie my %sorted, 'Tie::Hash::Indexed';
for my $k1 (sort keys $unsorted->%*) {
    for my $k2 (sort keys $unsorted->{$k1}->%*) {
        my $v = $unsorted->{$k1}{$k2};
        $v = [sort $v->@*] unless 'C' eq $k2;
        $sorted{$k1}{$k2} = $v;
    }
}
__END__
$HASH1 = {
    masterkeyA => {
        A => ['a', 'b', 'c'],
        B => ['a', 'b', 'c'],
        C => ['a', 'c', 'b'],
        D => ['a', 'b', 'c']
    },
    masterkeyB => {
        A => ['a', 'b', 'c'],
        B => ['a', 'b', 'c'],
        C => ['a', 'c', 'b'],
        D => ['a', 'b', 'c']
    }
};

答案 1 :(得分:1)

与数组不同,perl中的哈希不会保持排序顺序,因此常见的范例是在遍历数据结构时对哈希键进行排序。您需要的基本代码段是

for my $k ( sort keys %hash ) {
  for my $sk ( sort keys %{$hash->{$k}} ) {
    # do something
  }
}

以排序顺序访问哈希键,并且

if ( $k ne 'KEY' ) {
  # sort this array
  $hash->{$k} = sort @{$hash->{$k}}
}

对数组进行选择性排序。

例如,假设您要打印散列:

use strict;
use warnings;
use feature ':5.16';

my $data = {
      'masterkeyB' => {
            'D' => ['b', 'c', 'a'],
            'A' => ['b', 'a', 'c'],
            'C' => ['a', 'c', 'b'],
            'B' => ['a', 'c', 'b'],
          },
      'masterkeyA' => {
            'B' => ['a', 'c', 'b'],
            'C' => ['a', 'c', 'b'],
            'A' => ['b', 'a', 'c'],
            'D' => ['b', 'c', 'a'],
            }
    };


for my $mk ( sort keys %$data ) {
  say $mk;
  for my $letter ( sort keys %{$data->{$mk}} ) {
    say '  ' . $letter;
    if ( $letter eq 'C') {
      say '    [ ' . join(", ", @{$data->{$mk}{$letter}}) . ' ]';
    }
    else {
      say '    [ ' . join(", ", sort @{$data->{$mk}{$letter}}) . ' ]';
    }
  }
}

结果:

masterkeyA
  A
    [ a, b, c ]
  B
    [ a, b, c ]
  C
    [ a, c, b ]
  D
    [ a, b, c ]
masterkeyB
  A
    [ a, b, c ]
  B
    [ a, b, c ]
  C
    [ a, c, b ]
  D
    [ a, b, c ]

很明显,您可以更改say行以执行您打算对此数据进行的任何操作。

答案 2 :(得分:0)

我认为这可以满足您的需求。不容易准备,但可以工作。

my %sorted;
map {my $key = $_; map {$sorted{$key}->{$_} = ($_ eq 'C' ? $hash{$key}->{$_} : [sort @{$hash{$key}->{$_}}])} keys %{$hash{$key}}} keys %hash;

或对原始哈希进行排序

map {my $key = $_; map {$hash{$key}->{$_} = ($_ eq 'C' ? $hash{$key}->{$_} : [sort @{$hash{$key}->{$_}}])} keys %{$hash{$key}}} keys %hash;

或更短的版本

map {my $key = $_; map {$hash{$key}->{$_} = [sort @{$hash{$key}->{$_}}] if($_ ne 'C')} keys %{$hash{$key}}} keys %hash;