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 回答