converting a hash where the value is a list of lists to just a list

L

Lynn

Hi All,

I have a hash where the values are a list of lists. What I would like to do
is
convert this to a hash where the value is just a reference to an array that
contains
the list of lists. Below is my attempt to convert this to what I want, the
problem
is that I am loosing some people in the process!

use strict;
use warnings;
use Data::Dumper;
my %people = (
'hillrich' => [ [5308125], [2053628], [5312468], [5312492] ],
'hsieh' => [ [5312182], [5312613], [5312517] ],
'prakash' => [],
'florencb' => [
[1420688], [1420596], [5312242], [5306884], [5305217], [5248521],
],
'x_shukl' => []
);
my %new_format_people=();
foreach my $person(keys %people) {
foreach my $item (@{ $people{$person} }) {
for ( @$item) {
push @{$new_format_people{$person}},$_;
}
}
}

print Dumper(\%new_format_people);

output is:
$VAR1 = {
'hillrich' => [
5308125,
2053628,
5312468,
5312492
],
'hsieh' => [
5312182,
5312613,
5312517
],
'florencb' => [
1420688,
1420596,
5312242,
5306884,
5305217,
5248521
]
};

I lost prakash and x_shukl in the conversion process. How can I keep these
people
in the new hash I am creating?

Thanks

Lynn
 
P

Paul Lalli

Lynn said:
I have a hash where the values are a list of lists.

It's important to get the terminology correct. The values are
references to arrays of references to single-item arrays. (Contrary to
the naming of the perllol perldoc, there is no such thing as a "list of
lists").
What I would like to do is
convert this to a hash where the value is just a reference to an array that
contains the list of lists.

It looks to me as though what you wanted to do is convert the hash so
that the value is a reference to an array that contains all of the
values of the "inner" arrays.
Below is my attempt to convert this to what I want, the problem
is that I am loosing some people in the process!

use strict;
use warnings;
use Data::Dumper;
my %people = (
'hillrich' => [ [5308125], [2053628], [5312468], [5312492] ],
'hsieh' => [ [5312182], [5312613], [5312517] ],
'prakash' => [],
'florencb' => [
[1420688], [1420596], [5312242], [5306884], [5305217], [5248521],
],
'x_shukl' => []
);
my %new_format_people=();
foreach my $person(keys %people) {
foreach my $item (@{ $people{$person} }) {
for ( @$item) {
push @{$new_format_people{$person}},$_;

You're only adding any values to the %new_format_people hash within the
loop that goes through the existing list. If there are no values to
iterate over, no value will be added to the new hash.
I lost prakash and x_shukl in the conversion process. How can I keep these
people in the new hash I am creating?

I see two options. The least modification to your code would simply be
to explicitly add an empty array reference before attempting to copy
over the "inner" array values:

$new_format_people{$person} = [ ]; #this goes before the innermost for
loop

Alternatively, you could replace both inner for loops with one map
statement:
$new_format_people{$person} = [ map { $_->[0] } @{$people{$person}} ];

This creates a new entry in %new_format_people where the key is the
current person and the value is an array ref consisting of all the
values from "inner" arrays.

To make it more general, in case any of your "inner" arrays ever have
more than one element, replace $_->[0] with the entire array: @$_

Hope this helps,
Paul Lalli
 
J

John W. Krahn

Lynn said:
I have a hash where the values are a list of lists. What I would like to do
is convert this to a hash where the value is just a reference to an array
that contains the list of lists. Below is my attempt to convert this to what
I want, the problem is that I am loosing some people in the process!

use strict;
use warnings;
use Data::Dumper;
my %people = (
'hillrich' => [ [5308125], [2053628], [5312468], [5312492] ],
'hsieh' => [ [5312182], [5312613], [5312517] ],
'prakash' => [],
'florencb' => [
[1420688], [1420596], [5312242], [5306884], [5305217], [5248521],
],
'x_shukl' => []
);
my %new_format_people=();
foreach my $person(keys %people) {
foreach my $item (@{ $people{$person} }) {
for ( @$item) {
push @{$new_format_people{$person}},$_;
}
}
}

print Dumper(\%new_format_people);

$ perl -e'
use Data::Dumper;
my %people = (
hillrich => [ [5308125], [2053628], [5312468], [5312492] ],
hsieh => [ [5312182], [5312613], [5312517] ],
prakash => [],
florencb => [ [1420688], [1420596], [5312242], [5306884], [5305217],
[5248521], ],
x_shukl => [],
);
my %new_format_people = %people;
$_ = [ map ref() ? @$_ : $_, @$_ ] for values %new_format_people;
print Dumper \%new_format_people;
'
$VAR1 = {
'hillrich' => [
5308125,
2053628,
5312468,
5312492
],
'hsieh' => [
5312182,
5312613,
5312517
],
'florencb' => [
1420688,
1420596,
5312242,
5306884,
5305217,
5248521
],
'prakash' => [],
'x_shukl' => []
};




John
 
L

Lynn

Hi Paul,

Paul said:
It's important to get the terminology correct. The values are
references to arrays of references to single-item arrays. (Contrary
to the naming of the perllol perldoc, there is no such thing as a
"list of lists").
Ok


It looks to me as though what you wanted to do is convert the hash so
that the value is a reference to an array that contains all of the
values of the "inner" arrays.

yes, that is exactly what I wanted to do. Sorry for the confusion.
(snipped)

You're only adding any values to the %new_format_people hash within
the loop that goes through the existing list. If there are no values
to iterate over, no value will be added to the new hash.

I see that now. Thanks for pointing it out.
I lost prakash and x_shukl in the conversion process. How can I keep
these people in the new hash I am creating?

I see two options. The least modification to your code would simply
be to explicitly add an empty array reference before attempting to
copy over the "inner" array values:

$new_format_people{$person} = [ ]; #this goes before the innermost
for loop

Alternatively, you could replace both inner for loops with one map
statement:
$new_format_people{$person} = [ map { $_->[0] } @{$people{$person}} ];

This creates a new entry in %new_format_people where the key is the
current person and the value is an array ref consisting of all the
values from "inner" arrays.

This is exactly what I need :)
Hope this helps,

Thanks for all of your help Paul! :)
 
L

Lynn

Hi John,
(my stuff snipped)
$ perl -e'
use Data::Dumper;
my %people = (
hillrich => [ [5308125], [2053628], [5312468], [5312492] ],
hsieh => [ [5312182], [5312613], [5312517] ],
prakash => [],
florencb => [ [1420688], [1420596], [5312242], [5306884],
[5305217], [5248521], ],
x_shukl => [],
);
my %new_format_people = %people;
$_ = [ map ref() ? @$_ : $_, @$_ ] for values %new_format_people;
print Dumper \%new_format_people;

Wow, I need to study this! Thanks a lot :)
 
A

Anno Siegel

Lynn said:
Hi John,
(my stuff snipped)
$ perl -e'
use Data::Dumper;
my %people = (
hillrich => [ [5308125], [2053628], [5312468], [5312492] ],
hsieh => [ [5312182], [5312613], [5312517] ],
prakash => [],
florencb => [ [1420688], [1420596], [5312242], [5306884],
[5305217], [5248521], ],
x_shukl => [],
);
my %new_format_people = %people;
$_ = [ map ref() ? @$_ : $_, @$_ ] for values %new_format_people;
print Dumper \%new_format_people;

Wow, I need to study this! Thanks a lot :)

Here is a way to do it in place:

for ( values %people ) {
$_ = $_->[ 0] for @$_;
}

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,742
Latest member
AshliMayer

Latest Threads

Top