List Info

Thread: Re: Transforming a list into a hash of arrays




Re: Transforming a list into a hash of arrays
country flaguser name
United States
2007-02-07 18:36:03
--- In perl-beginner@yahoogroups.com, Rob Biedenharn
<Rob...> wrote:
>
> 
> On Feb 7, 2007, at 10:58 AM, jslay77 wrote:
> 
> > I hope this is the appropriate forum to ask this
question.
> >
> > assume I have a list like this:
> >
> > input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3', '2',
> > 'hostname10', '2', 'hostname11', '3',
'hostname12');
> >
> > I want to turn this list into a hash of anonymous
arrays...something
> > like this I guess.
> >
> > %hash = (
> > '1' => ['hostname1', 'hostname2',
'hostname3'],
> > '2' => ['hostname10', 'hostname11'],
> > '3' => ['hostname12'],
> > );
> >
> >
> > 
> >
> > I hope I explained that appropriately.
> > regards,
> > J
> 
> Why don't you post some code showing your attempt and
then we can  
> help you if it doesn't do what you expect?  Here's a
hint, to  
> initialize a hash element with an empty array if it
doesn't already  
> have a value, you can do this:
> 
>          $hash{$key} ||= [];
> 
> I made a subroutine "array_to_hash" taking a
list of values and  
> returning a hash.  My little script also used  
> List::MoreUtils::natatime to get the pairs from the
array, but that's  
> not the only way.  I also used Data:umper to
produce the output to  
> visually check the result like this:
> 
> 
> input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3', '2',
>            'hostname10', '2', 'hostname11', '3',
'hostname12');
> 
> my %hash = array_to_hash input;
> 
> print Data:umper-&g
t;Dump([input, %hash], [qw(*input *hash)]);
> 
> input = (
>             '1',
>             'hostname1',
>             '1',
>             'hostname2',
>             '1',
>             'hostname3',
>             '2',
>             'hostname10',
>             '2',
>             'hostname11',
>             '3',
>             'hostname12'
>           );
> %hash = (
>            '1' => [
>                     'hostname1',
>                     'hostname2',
>                     'hostname3'
>                   ],
>            '3' => [
>                     'hostname12'
>                   ],
>            '2' => [
>                     'hostname10',
>                     'hostname11'
>                   ]
>          );
> 
> -Rob
> 
> Rob Biedenharn		http://agileconsultingl
lc.com
> Rob...
>

Rob,

Thanks for the quick response...and your $hash{$key} ||=[]
hint 

I actually got around this whole thing by retrieving my data
differently from DBD::Oracle, 
however I was still intrigued at the problem...I believe I
figured it out with your help.

This does what I was looking for, however would there be a
better way?

input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3', '2', 'hostname10', '2', 
'hostname11', '3', 'hostname12');
my %hash;

my %seen;
my $key;
for (input; $i <= $#input; $i += 2) {
    if (! $seen{$input[$i]}++ ) {
        $hash{$input[$i]} ||= ["$input[$i + 1]"];
    } else {
        push {$hash{$input[$i]}}, $input[$i + 1];
        next;
    }
}


foreach (sort keys %hash) {
    print "$_ --> {$hash{$_}}n";
}



Unsubscribing info is here: h
ttp://help.yahoo.com/help/us/groups/groups-32.html 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://g
roups.yahoo.com/group/perl-beginner/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http
://groups.yahoo.com/group/perl-beginner/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:perl-beginner-digest@yahoogroups.com 
    mailto:perl-beginner-fullfeatured@yahoogroups.com

<*> To unsubscribe from this group, send an email to:
    perl-beginner-unsubscribe@yahoogroups.com

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.c
om/info/terms/
 

Re: Re: Transforming a list into a hash of arrays
country flaguser name
United States
2007-02-07 19:24:07
On Feb 7, 2007, at 7:36 PM, jslay77 wrote:
> --- In perl-beginner@yahoogroups.com, Rob Biedenharn
<Rob...> wrote:
>> On Feb 7, 2007, at 10:58 AM, jslay77 wrote:
>>> I hope this is the appropriate forum to ask
this question.
>>>
>>> assume I have a list like this:
>>>
>>> input = ('1', 'hostname1', '1',
'hostname2', '1', 'hostname3', '2',
>>> 'hostname10', '2', 'hostname11', '3',
'hostname12');
>>>
>>> I want to turn this list into a hash of
anonymous arrays...something
>>> like this I guess.
>>>
>>> %hash = (
>>> '1' => ['hostname1', 'hostname2',
'hostname3'],
>>> '2' => ['hostname10', 'hostname11'],
>>> '3' => ['hostname12'],
>>> );
>>>
>>>
>>> 
>>>
>>> I hope I explained that appropriately.
>>> regards,
>>> J
>>
>> Why don't you post some code showing your attempt
and then we can
>> help you if it doesn't do what you expect?  Here's
a hint, to
>> initialize a hash element with an empty array if it
doesn't already
>> have a value, you can do this:
>>
>>          $hash{$key} ||= [];
>>
>> I made a subroutine "array_to_hash"
taking a list of values and
>> returning a hash.  My little script also used
>> List::MoreUtils::natatime to get the pairs from the
array, but that's
>> not the only way.  I also used Data:umper to
produce the output to
>> visually check the result like this:
>>
>>
>> input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3', '2',
>>            'hostname10', '2', 'hostname11', '3',
'hostname12');
>>
>> my %hash = array_to_hash input;
>>
>> print Data:umper-&g
t;Dump([input, %hash], [qw(*input *hash)]);
>>
>>
>> -Rob
>>
>> Rob Biedenharn		http://agileconsultingl
lc.com
>> Rob...
>>
>
> Rob,
>
> Thanks for the quick response...and your $hash{$key}
||=[] hint 
>
> I actually got around this whole thing by retrieving my
data  
> differently from DBD::Oracle,
> however I was still intrigued at the problem...I
believe I figured  
> it out with your help.
>
> This does what I was looking for, however would there
be a better way?
>
> input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3',  
> '2', 'hostname10', '2',
> 'hostname11', '3', 'hostname12');
> my %hash;
>
> my %seen;
You don't need this...

> my $key;
You haven't used this...

But you don't initialize $i (which tells me that you aren't
using the  
-w option)

> for (input; $i <= $#input; $i += 2) {
Should be < not <=, but you get lucky since you're
incrementing by 2
>     if (! $seen{$input[$i]}++ ) {
>         $hash{$input[$i]} ||= ["$input[$i +
1]"];
Unless you mean to stringify the values, you don't need the
quotes  
just like you don't need them in the push.
>     } else {
>         push {$hash{$input[$i]}}, $input[$i + 1];
>         next;
>     }
> }

Simplifying and you get (after really using the hint 
for (my $i = 0; $i < $#input; $i += 2) {
     push {$hash{$input[$i]} ||= []},  $input[$i + 1];
}

> foreach (sort keys %hash) {
>     print "$_ --> {$hash{$_}}n";
> }

And for completeness now that you've done your version. 
Here's mine:

#!/usr/bin/env perl -w
use List::MoreUtils qw(natatime);
use Data:umper;

sub array_to_hash {
     my args = _;
     my %hash;

     my $iter = natatime 2, args;
     while (my ($key, $val) = $iter->()) {
         $hash{$key} ||= [];
         push {$hash{$key}}, $val;
     }
     return %hash;
}

input = ('1', 'hostname1', '1', 'hostname2', '1',
'hostname3', '2',
           'hostname10', '2', 'hostname11', '3',
'hostname12');
my %hash = array_to_hash input;

print Data:umper-&g
t;Dump([input, %hash], [qw(*input *hash)]);

__END__

I could have (should have) made the loop body be the single
line:
         push {$hash{$key} ||= []}, $val;

I hope that make sense.  The Data:umper
library is quite handy to  
do quick views of data structures when they grow beyond
simple arrays  
and hashes.  You might want to check out List::MoreUtils
(and  
List::Util) for a number of useful manipulations of lists
(aka, arrays).

-Rob

Rob Biedenharn		http://agileconsultingl
lc.com
RobAgileConsultingLLC.com




Unsubscribing info is here: h
ttp://help.yahoo.com/help/us/groups/groups-32.html 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://g
roups.yahoo.com/group/perl-beginner/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http
://groups.yahoo.com/group/perl-beginner/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:perl-beginner-digest@yahoogroups.com 
    mailto:perl-beginner-fullfeatured@yahoogroups.com

<*> To unsubscribe from this group, send an email to:
    perl-beginner-unsubscribe@yahoogroups.com

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.c
om/info/terms/
 

[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )