【问题标题】:Perl, Sort nested hashPerl,排序嵌套哈希
【发布时间】:2018-12-17 20:14:38
【问题描述】:

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

$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”外,所有数组均已排序。

【问题讨论】:

    标签: perl hash hashtable


    【解决方案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']
        }
    };
    

    【讨论】:

    • 确实排序,见for my $k2 (sort keys …行。
    • 第一行不只是为了好玩!它可以防止语法错误!当你修改我的代码,运行它,得到一个错误然后假装是我的错时,我不喜欢它。 – 我将其更改为 feature 以更清楚地了解发生了什么。 - 您可以升级到supported version of Perl(我认为这对每个人来说都是最好的)或更改代码以使用您不支持的版本,postderef ->@* 在表达式周围变为@{ … },并与% sigil 模拟
    【解决方案2】:

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

    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 行来执行您计划对这些数据执行的任何操作。

    【讨论】:

      【解决方案3】:

      我认为这可以满足您的需求。不容易准备好,但很有效。

      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;
      

      【讨论】:

        猜你喜欢
        • 2012-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-20
        • 2020-12-09
        • 2016-09-05
        • 2013-09-21
        • 1970-01-01
        相关资源
        最近更新 更多