从哈希列表创建多级哈希

时间:2012-09-18 18:02:45

标签: perl

我正在尝试编写一个子类,它可以获取哈希列表并根据任意数量的字段的内容创建一个嵌套列表。我只是无法正确设置递归。我从数据库中获取了一堆bug数据,并希望将数据分组到任意字段列表(团队,优先级等)。我真的没有任何我认为甚至足够接近的示例代码

以下示例

我有以下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',
                       }
              }

        };

2 个答案:

答案 0 :(得分: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" }] },
}

答案 1 :(得分: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 \$_, @_);
}