2

I am trying to create a hash of hash of - the nesting depth depends on the number of arguments passed into @aGroupByFields array.

In the below implementation, I am getting the desired hash structure.But I have hard coded the fields [ example - $phBugRecord->{createdBy} ] instead of deriving it from the array.

I am not sure how to dynamically create this.

my (@aGroupByFields) = ['createdBy','status','devPriority']; 
# In real case,these are passed in as arguments

my (%hTemp); 
# This is the final hash which will be structured according to above fields

# %hBugDetails is the hash containing details of all bugs

foreach my $phBugRecord ( @{ $hBugDetails{records} } ) {

    # The below statement needs to be generated dynamically as 
    # opposed to the hard-coded values.
    push(
        @{
            $hTemp{ $phBugRecord->{createdBy} }{ $phBugRecord->{status} }
                { $phBugRecord->{devPriority} }
        },
        $phBugRecord
    );

}

Any pointer will be a great help.Thanks.

7
  • 1
    You don't want to generate the statement. You want to generate the hash. But why do you want that? Commented Mar 16, 2016 at 11:02
  • 1
    Please refer below question: stackoverflow.com/questions/4558981/… I hope that helps! Commented Mar 16, 2016 at 11:09
  • See Data::Diver and Deep::Hash::Utils Commented Mar 16, 2016 at 11:30
  • @simbabque : The hash, thus generated , will be consumed to render a bug report.The bug report will be then able to show the bugs grouped by createdBy > status > devPriority. [ In short, I am given a list of groupBy fields and a dump of all bug records - and I need to return a hash which should group the bug records appropriately].Thanks for the edit anyways.Cheers. Commented Mar 16, 2016 at 11:40
  • 1
    @HåkonHægland I didn't know Data::Diver. That's fun, especially that it can be an lvalue. :) Commented Mar 16, 2016 at 12:04

2 Answers 2

2

Here is a working implementation with Data::Diver.

use strict;
use warnings;
use Data::Diver 'DiveVal';
use Data::Printer;

my %hBugDetails = (
    records => [
        {
            createdBy   => 'created_by1',
            status      => 'status1',
            devPriority => 'dev_priority1',
            foo         => 'foo1',
            bar         => 'bar1',
        },
        {
            createdBy   => 'created_by1',
            status      => 'status2',
            devPriority => 'dev_priority2',
            foo         => 'foo',
            bar         => 'bar',
        },
    ],
);

# we want to group by these fields
my @group_by = ( 'createdBy', 'status', 'devPriority' );

my $grouped_bugs = {};    # for some reason we need to start with an empty hashref
foreach my $bug ( @{ $hBugDetails{records} } ) {

    # this will auto-vivify the hash for us
    push @{ DiveVal( $grouped_bugs, map { $bug->{$_} } @group_by ) }, $bug;
}

p $grouped_bugs;

The output looks like this.

\ {
    created_by1   {
        status1   {
            dev_priority1   [
                [0] {
                    bar           "bar1",
                    createdBy     "created_by1",
                    devPriority   "dev_priority1",
                    foo           "foo1",
                    status        "status1"
                }
            ]
        },
        status2   {
            dev_priority2   [
                [0] {
                    bar           "bar",
                    createdBy     "created_by1",
                    devPriority   "dev_priority2",
                    foo           "foo",
                    status        "status2"
                }
            ]
        }
    }
}

Note that I renamed your variables. It was very hard to read the code like that. It makes more sense to just use speaking names instead of cryptic abbreviations for the type of variable. The sigil already does that for you.

Sign up to request clarification or add additional context in comments.

Comments

1

This code will do what you need

my @aGroupByFields = qw/ createdBy status devPriority /;

my %hTemp;

for my $phBugRecord ( @{ $hBugDetails{records} } ) {

    my $hash = \%hTemp;

    for my $field ( @aGroupByFields ) {

        my $key = $phBugRecord->{$field};

        if ( $field eq $aGroupByFields[-1] ) {
            push @{ $hash->{ $key } }, $phBugRecord;
        }
        else {
            $hash = $hash->{ $key } //= {};
        }
    }
}

1 Comment

This worked like a charm.Gave me back exactly what I wanted.I know I am asking for too much here - can you please explain the code $hash = $hash->{ $key } //= {}; Thanks a lot for your input.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.