Perl group cast to hash using fetchrow_hashref

I want to group my results by countryid with the data shown below.

my @test = ();
my $st   = qq[
    SELECT id,countryID,abbrev
    FROM myTable
];
my $q = $data->prepare($st);
$q->execute() or query_error($st);
while ( my $result = $q->fetchrow_hashref ) {
    push @test, $result;
}

      

Using fetchrow_hashref I have no problem displaying the results

use Data::Dumper;
print STDERR Dumper(\@test);

      

returns

$VAR1 = [
    {   'id'        => '1',
        'countryID' => '1',
        'title'     => 'Title 1',
        'abbrev'    => 't1'
    },
    {   'id'        => '2',
        'countryID' => '2',
        'title'     => 'Title 2',
        'abbrev'    => 't2'
    },
    {   'id'        => '3',
        'countryID' => '3',
        'title'     => 'Title 3',
        'abbrev'    => 't3'
    },
    {   'id'        => '4',
        'countryID' => '1',
        'title'     => 'Title 4',
        'abbrev'    => 't4'
    }
];

      

I want to group it by country as shown below.

$VAR1 = [
    'countries' => {
        '1' => [
            {   'id'     => '1',
                'title'  => 'Title 1',
                'abbrev' => 't1'
            },
            {   'id'     => '4',
                'title'  => 'Title 4',
                'abbrev' => 't4'
            }
        ],
        '2' => [
            {   'id'     => '2',
                'title'  => 'Title 2',
                'abbrev' => 't2'
            }
        ],
        '3' => [
            {   'id'     => '3',
                'title'  => 'Title 3',
                'abbrev' => 't3'
            }
        ]
    }
];

      

How can I get this to work in a while loop?

+3


source to share


3 answers


You need to correct your syntax a bit (like =>

instead = >

), but once you've done that, something like this should work well.

for (@$VAR1_orig) {
    my %a = %$_;
    my $countryID = $a{countryID};
    delete $a{countryID};
    push @{$VAR1->{countries}{$countryID}}, \%a;
}

      



(By the way, I tried this on my computer, it works.)

The above assumes it is %$VAR1

initially empty, then fills it in according to @$VAR1_orig

, after which you can do with $VAR1

whatever you like. (I assume you know what Perl means as %$

well @$

, but this is not a newbie as you know. See man 1 perlref

.)

+1


source


Ignoring errors in your sample data structure, you basically want to convert an array of hash shapes to a hash hash of an array of hashes. After setting up the original data structure, you can do the following to create a new nested data structure:

for my $href ( @test ) {
    my $id = $href->{countryID};
    delete $href->{countryID};
    push @{ $test2->{countries}{$id} }, $href;
}

      

Iterate over each element of your array @test

, which is basically an array of hash references. Create a variable $id

that will grab the value countryID

from the hash. We remove it from the hash reference and then assign this hash reference to our new nested data structure, which has countries

both the first level key

and $id

the second level key.



We use the syntax push

to create our array of such links.

Note: As thb pointed out in the comments, this destroys your original data structure. If you want to keep the original structure, change your code to the following:

for my $href ( @test ) {
    my $copy = { %$href };
    my $id   = $copy->{countryID};
    delete $copy->{countryID};
    push @{ $test2->{countries}{$id} }, $copy;
}

      

+2


source


Something like this, the I / O data structures may not be exactly what you have or want, you can fix that.

use strict;
use Data::Dumper;

$a = [
    {   'id'        => '1',
        'countryID' => '1',
        'title'     => 'Title 1',
        'abbrev'    => 't1'
    },
    {   'id'        => '2',
        'countryID' => '2',
        'title'     => 'Title 2',
        'abbrev'    => 't2'
    },
    {   'id'        => '3',
        'countryID' => '3',
        'title'     => 'Title 3',
        'abbrev'    => 't3'
    },
    {   'id'        => '4',
        'countryID' => '1',
        'title'     => 'Title 4',
        'abbrev'    => 't4'
    }
];

my $b = {};

for my $item (@$a) {
    if ( exists( $b->{ $item->{'countryID'} } ) ) {
        push( @{ $b->{ $item->{'countryID'} } }, $item );
    } else {
        $b->{ $item->{'countryID'} } = [$item];
    }
}
print Dumper($b);

      

The above prints:

$VAR1 = {
    '1' => [
        {   'abbrev'    => 't1',
            'title'     => 'Title 1',
            'id'        => '1',
            'countryID' => '1'
        },
        {   'abbrev'    => 't4',
            'title'     => 'Title 4',
            'id'        => '4',
            'countryID' => '1'
        }
    ],
    '3' => [
        {   'abbrev'    => 't3',
            'title'     => 'Title 3',
            'id'        => '3',
            'countryID' => '3'
        }
    ],
    '2' => [
        {   'abbrev'    => 't2',
            'title'     => 'Title 2',
            'id'        => '2',
            'countryID' => '2'
        }
    ]
};

      

+1


source







All Articles