Perl:具有group_by函数的模块,用于将hashrefs数组转换为arrayrefs的hash

时间:2017-05-02 03:38:24

标签: perl

给定一个hashrefs数组:

my @items = (
    {
        key   => 'a-key',
        value => 'a-value-1',
    },
    {
        key   => 'a-key',
        value => 'a-value-2',
    },
    {
        key   => 'b-key',
        value => 'b-value-1',
    },
    {
        key   => 'b-key',
        value => 'b-value-2',
    },
);

我想生成一个散列值,其中的值存储在按键分组的arrayrefs中:

my %grouped = (
    'a-key' => ['a-value-1', 'a-value-2'],
    'b-key' => ['b-value-1', 'b-value-2'],
);

我知道这可以通过循环遍历元素来原生:

my %grouped;
for my $item (@items) {
    push @{ $grouped{$item->{key}} }, $item->{value};
}

但它似乎是一个通用的公式,因为有一个模块可以提供类似于RubyUnderscore JS按功能分组的功能。 Perl中是否有一个常用的库提供类似的功能?

如果有人提到List::Util::reduce,那对我来说似乎没有那么复杂,而且使用它来制作一个hashref似乎很尴尬。

my $grouped = reduce {
    push @{ $a->{$b->{key}} }, $b->{value};
    $a;
} {}, @items;

我想象这样的用法:

my %grouped = group_by { $_->{key} } @items;

编辑:我刚刚意识到,如果我们使用上面的group_by,我们仍然需要进一步处理结果,如下所示:

for my $arrayref (values %grouped) {
    $_ = $_->{value} for @$arrayref;
}

1 个答案:

答案 0 :(得分:3)

似乎没有图书馆功能,所以我自己写了一个。

sub group_by (&@) {
    my ($get_kv, @items) = @_;

    my %groups;
    for (@items) {
        my ($k, $v) = ($get_kv->(), $_);
        push @{ $groups{$k} }, $v;
    }
    %groups;
}

在块内,第一个元素指定要分组的键,第二个元素可选地指定要分组的值。如果未提供第二个元素,则将整个项目用作值。

用法:

my %keys_to_values = group_by { $_->{key}, $_->{value} } @items;
# (
#     'a-key' => [qw(a-value-1 a-value-2)],
#     'b-key' => [qw(b-value-1 b-value-2)],
# )

my %keys_to_items = group_by { $_->{key} } @items;
# (
#    'a-key' => [
#        {
#            key   => 'a-key',
#            value => 'a-value-1',
#        },
#        {
#            key   => 'a-key',
#            value => 'a-value-2',
#        },
#    ],
#    'b-key' => [
#        {
#            key   => 'b-key',
#            value => 'b-value-1',
#        },
#        {
#            key   => 'b-key',
#            value => 'b-value-2',
#        },
#    ],
# )