2
my %data (
    KEY1 => {
        SUBKEY1 => "Canada",
        SUBKEY3 => "75.00",
        SUBKEY2 => "50.00",    
    },
    KEY3 => {
        SUBKEY2 => "150.00",
    },  
    KEY2 => { 
        SUBKEY3 => "200.00",
        SUBKEY1 => "Mexico",
 },
);

如何打印按键名排序的列表以及按子键名排序的每个键名?

这是我要打印的内容:(请注意,如果未定义子键,则存在带有空字符串的子键的占位符)

KEY1: SUBKEY1 is "Canada"
KEY1: SUBKEY2 is "50.00"
KEY1: SUBKEY3 is "75.00"
KEY2: SUBKEY1 is ''
KEY2: SUBKEY2 is "150.00"
KEY2: SUBKEY3 is ''
KEY3: SUBKEY1 is "Mexico"
KEY3: SUBKEY2 is ''
KEY3: SUBKEY3 is "200.00"
4

3 回答 3

3

施瓦茨变换怎么样?

#! /usr/bin/perl

use 5.10.0;  # for // (aka defined-or)
use warnings;
use strict;

my %data = ...;

# get all subkeys used in %data
my @subkeys = keys %{
  { map { map +($_ => 1),
          keys %{ $data{$_} } }
    keys %data
  }
};

print map qq|$_->[0]: $_->[1] is "$_->[2]"\n|,
      sort { $a->[0] cmp $b->[0]
                     ||
             $a->[1] cmp $b->[1] }
      map { my $key = $_;
            map [ $key, $_, $data{$key}{$_} // "" ] =>
            @subkeys }
      keys %data;

请记住从后到前阅读 Schwartzian 变换。第一个 - 最接近结尾 - <code>map%data以某种未指定的顺序展平或“反规范化”为记录列表。嵌套map是到达子键所必需的。要处理任意深度的嵌套,请flatten递归定义。

我们进行了较早的传递以收集所有使用的子键,因此如果不存在特定的子键,则值为$data{$key}{$_}未定义的值。使用//5.10.0 版中的定义或运算符 new 指定默认值"".

带有扁平化的表格记录

[ "KEY1", "SUBKEY3", "75.00" ],
[ "KEY1", "SUBKEY1", "Canada" ],
...

排序很简单:比较各自的第一个元素(键),如果它们相等,则回退到秒(子键)。

最后,最外层map格式化现在排序的非规范化记录以供输出,结果列表通过运算符进入标准输出print

输出:

KEY1:SUBKEY1 是“加拿大”
KEY1:SUBKEY2 是“50.00”
KEY1:SUBKEY3 是“75.00”
KEY2:SUBKEY1 是“墨西哥”
KEY2: SUBKEY2 是 ""
KEY2:SUBKEY3 是“200.00”
KEY3: SUBKEY1 是 ""
KEY3:SUBKEY2 是“150.00”
KEY3: SUBKEY3 是 ""

要将子键与每个子键的相应键分组在同一行,请使用以下代码

my @subkeys = sort keys %{ ... ;

foreach my $key (sort keys %data) {
  my @values;
  foreach my $subkey (@subkeys) {
    my $value = $data{$key}{$subkey} // "";
    push @values => qq|$subkey is "$value"|;
  }

  local $" = ", ";
  print "$key: @values\n";
}

你可以用函数式的风格来写它,但结果是一团糟:

print map { my $key = $_;
            "$key: " .
              join(", " =>
                map { my $value = $data{$key}{$_} // "";
                      qq|$_ is "$value"|
                    }
                @subkeys) .
            "\n"
          }
      sort keys %data;

输出:

KEY1:SUBKEY1 为“加拿大”,SUBKEY2 为“50.00”,SUBKEY3 为“75.00”
KEY2:SUBKEY1 是“墨西哥”,SUBKEY2 是“”,SUBKEY3 是“200.00”
KEY3:SUBKEY1为“”,SUBKEY2为“150.00”,SUBKEY3为“”
于 2010-07-08T19:32:17.247 回答
3
use strict;
use warnings;

my %data = (
    KEY1 => {
        SUBKEY1 => "Canada",
        SUBKEY3 => "75.00",
        SUBKEY2 => "50.00",    
    },
    KEY3 => {
        SUBKEY2 => "150.00",
    },  
    KEY2 => { 
        SUBKEY3 => "200.00",
        SUBKEY1 => "Mexico",
 },
);

my %all_sub_keys;
for my $sub_hash (values %data){
    $all_sub_keys{$_} ++ for keys %$sub_hash;
}

my @all_sub_keys = sort keys %all_sub_keys;

for my $k ( sort keys %data ){
    for my $sk (@all_sub_keys){
        my $val = exists $data{$k}{$sk} ? $data{$k}{$sk} : '--';
        print join(' ', $k, $sk, $val), "\n";
    }
}
于 2010-07-08T19:02:02.810 回答
2

我假设这组子键是提前知道的。

#!/usr/bin/perl

use strict; use warnings;

my %data = (
    KEY1 => {
        SUBKEY1 => "Canada",
        SUBKEY3 => "75.00",
        SUBKEY2 => "50.00",
    },
    KEY3 => {
        SUBKEY2 => "150.00",
    },
    KEY2 => {
        SUBKEY3 => "200.00",
        SUBKEY1 => "Mexico",
 },
);

my @subkeys = qw( SUBKEY1 SUBKEY2 SUBKEY3 );

for my $key ( sort keys %data ) {
    my %sub = map {
        my $v = $data{$key}{$_};
        $_ => defined($v) ? $v : '';
    } @subkeys;

    for my $subkey ( @subkeys ) {
        print "$key $subkey $sub{$subkey}\n";
    }
}

输出:

KEY1 SUBKEY1 加拿大
密钥 1 子密钥 2 50.00
密钥 1 子密钥 3 75.00
KEY2 SUBKEY1 墨西哥
键 2 子键 2
密钥 2 子密钥 3 200.00
键 3 子键 1
密钥 3 子密钥 2 150.00
键 3 子键 3
于 2010-07-08T19:07:27.353 回答