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
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 に答える
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;

シュワルツ変換を後ろから前に読むことを忘れないでください。最初の (最後に最も近い) <code>map は%data、不特定の順序でレコードのリストにフラット化または「非正規化」します。mapサブキーに到達するには、入れ子になっている必要があります。任意の深いネストを処理するには、flatten再帰的に定義します。

使用されるすべてのサブキーを収集するために以前のパスを作成したため、特定のサブキーが存在しない場合、の値$data{$key}{$_}は未定義の値になります。//バージョン 5.10.0 で新しく追加された定義済み OR 演算子を使用して、デフォルト値の を指定します""

フォームの平坦化されたレコードを使用

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

並べ替えは簡単です。それぞれの最初の要素 (キー) を比較し、それらが等しい場合は、秒 (サブキー) に戻ります。

最後に、最も外側mapで、ソートされた非正規化レコードを出力用にフォーマットし、結果のリストを演算子を介して標準出力にprint渡します。

出力:

KEY1: SUBKEY1 は「カナダ」
KEY1: SUBKEY2 は「50.00」
KEY1: SUBKEY3 は「75.00」
KEY2: SUBKEY1 は「メキシコ」
KEY2: サブキー2 は ""
KEY2: SUBKEY3 は「200.00」
KEY3: サブキー1は「」
KEY3: サブキー2は「150.00」
KEY3: サブキー3 は ""

サブキーをそれぞれのキーと同じ行にグループ化するには、次のようなコードを使用します。

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 に答える
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";
    }
}

出力:

KEY1SUBKEY1カナダ
KEY1 SUBKEY2 50.00
KEY1 SUBKEY3 75.00
KEY2SUBKEY1メキシコ
KEY2 SUBKEY2
KEY2 SUBKEY3 200.00
KEY3 SUBKEY1
KEY3 SUBKEY2 150.00
KEY3 SUBKEY3
于 2010-07-08T19:07:27.353 に答える