0

ハッシュのリストを取り、任意の数のフィールドの内容に基づいてネストされたリストを作成できるサブを作成しようとしています。再帰のセットアップを正しく取得できません。データベースから大量のバグ データを取得しており、フィールドの任意のリスト (チーム、優先度など) でデータをグループ化したいと考えています。十分に近づいていると思うサンプルコードは本当にありません

以下の例

次の DS があります。

$ds =
[
  {
    foo => 'A',
    bar => 'B',
    baz => 'C',
  },
  {
    foo => 'A',
    bar => 'B',
    baz => 'F',
  },
  {
    foo => 'A',
    bar => 'D',
    baz => 'G',
  },
  {
    foo => 'R',
    bar => 'J',
    baz => 'G',
  }
]

次の関数呼び出しが与えられた場合

# prototype   groupBy(data, field-1,field-2,field-n)
groupBy($ds,'foo','bar');

次の出力が欲しい

$res = {
         A => {
                B => [
                       {
                         foo => 'A',
                         bar => 'B', 
                         baz => 'C',
                       }, 
                       {
                         foo => 'A',
                         bar => 'B',
                         baz => 'F',
                       }
                     ],
                D => [
                       {
                         foo => 'A',
                         bar => 'D',
                         baz => 'G', 
                       }
                     ],
              },
         R => {
                J => [
                       {
                          foo => 'R',
                          bar => 'J',
                          baz => 'G',
                       }
              }

        };
4

2 に答える 2

1

これは、再帰的アプローチを使用すると非常に簡単です

次のコードは

use strict;
use warnings;

my $ds = [
  { bar => "B", baz => "C", foo => "A" },
  { bar => "B", baz => "F", foo => "A" },
  { bar => "D", baz => "G", foo => "A" },
  { bar => "J", baz => "G", foo => "R" },
];

my $grouped = groupBy($ds, qw/ foo bar /);

use Data::Dump;
dd $grouped;

sub groupBy {

  my ($ds, $key, @rest) = @_;
  return $ds unless $key;

  my %groups;
  push @{ $groups{$_->{$key}} }, $_ for @$ds;
  $groups{$_} = groupBy($groups{$_}, @rest) for keys %groups;

  return \%groups;
}

出力

{
  A => {
         B => [
                { bar => "B", baz => "C", foo => "A" },
                { bar => "B", baz => "F", foo => "A" },
              ],
         D => [{ bar => "D", baz => "G", foo => "A" }],
       },
  R => { J => [{ bar => "J", baz => "G", foo => "R" }] },
}
于 2012-09-18T18:25:12.947 に答える
0

ハードコーディングされたソリューション:

my $res;
for (@$ds) {
   push @{ $res->{ $_->{foo} }{ $_->{bar} } }, $_;
}

しかし、キーの可変長リストをサポートしたいとします。少しだけループを追加します。

sub groupBy {
    my ($ds, @keys) = @_;
    my $res;
    for (@$ds) {
       my $p = dive($res, @$_{ @keys });
       push @$$p, $_;
    }
   return $res;
}

diveどちらかはどこですか

sub dive {
   my $p = \shift;
   $p = \( $$p->{$_} ) for @_;
   return $p;
}

また

use Data::Diver qw( DiveRef );
sub dive {
   $_[0] //= {};
   return DiveRef(shift, map \$_, @_);
}
于 2012-09-18T18:20:20.417 に答える