Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Spliting values and reversing a hash

Reply
Thread Tools

Spliting values and reversing a hash

 
 
mlwollman@gmail.com
Guest
Posts: n/a
 
      10-04-2006
Hello all,

I'm very, very new to Perl, and I have a question I can't quite find
the answer in the O'Reilly Perl books (Learning, Programming, and
Cookbook). Any assistance would be helpful.

I have a hash with key value pairs like:
1 => Chocolate,Vanilla,Rocky Road
2 => Strawberry,Vanilla, Pistachio
3 => Cookie Dough,Chocolate
4 => Strawberry,Pistachio

And I need to transform it to:
Chocolate => 1,3
Vanilla => 1,2
Rocky Road => 1
Strawberry => 2,4
Pistachio =>2,4
Cookie Dough => 3

What's a good, simple way to do that?

I thought about using while each and changing the value to an array and
foreach array element make a new has with the array element as a key
and the old key join() any existing values, I think. I'm pretty
confused now.

Thank You,
Matt

 
Reply With Quote
 
 
 
 
Bob Walton
Guest
Posts: n/a
 
      10-04-2006
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
....
> I have a hash with key value pairs like:
> 1 => Chocolate,Vanilla,Rocky Road
> 2 => Strawberry,Vanilla, Pistachio
> 3 => Cookie Dough,Chocolate
> 4 => Strawberry,Pistachio
>
> And I need to transform it to:
> Chocolate => 1,3
> Vanilla => 1,2
> Rocky Road => 1
> Strawberry => 2,4
> Pistachio =>2,4
> Cookie Dough => 3
>
> What's a good, simple way to do that?
>
> I thought about using while each and changing the value to an array and
> foreach array element make a new has with the array element as a key
> and the old key join() any existing values, I think. I'm pretty
> confused now.

....
> Matt
>


Here is one way, which is pretty much what you described, except I
elected to use strings rather than arrays since I think you said you
wanted strings:

use warnings;
use strict;
use Data:umper;
my %h; #original hash
$h{1}='Chocolate,Vanilla,Rocky Road';
$h{2}='Strawberry,Vanilla,Pistachio';
$h{3}='Cookie Dough,Chocolate';
$h{4}='Strawberry,Pistachio';
my %h1; #flavors hash
for(sort keys %h){
my @v=split /,/,$h{$_}; #separate flavors
for my $v(@v){
$h1{$v}.="$_,"; #add number to flavor
}
}
for(keys %h1){
$h1{$_}=~s/,$//; #get rid of trailing commas
}
print Dumper(\%h1);

--
Bob Walton
Email: http://bwalton.com/cgi-bin/emailbob.pl
 
Reply With Quote
 
 
 
 
John W. Krahn
Guest
Posts: n/a
 
      10-04-2006
(E-Mail Removed) wrote:
>
> I'm very, very new to Perl, and I have a question I can't quite find
> the answer in the O'Reilly Perl books (Learning, Programming, and
> Cookbook). Any assistance would be helpful.
>
> I have a hash with key value pairs like:
> 1 => Chocolate,Vanilla,Rocky Road
> 2 => Strawberry,Vanilla, Pistachio
> 3 => Cookie Dough,Chocolate
> 4 => Strawberry,Pistachio
>
> And I need to transform it to:
> Chocolate => 1,3
> Vanilla => 1,2
> Rocky Road => 1
> Strawberry => 2,4
> Pistachio =>2,4
> Cookie Dough => 3
>
> What's a good, simple way to do that?


$ perl -le'
use Data:umper;

my %hash = (
1 => [ "Chocolate", "Vanilla", "Rocky Road" ],
2 => [ "Strawberry", "Vanilla", "Pistachio" ],
3 => [ "Cookie Dough", "Chocolate" ],
4 => [ "Strawberry", "Pistachio" ],
);

print Dumper \%hash;

for my $key ( keys %hash ) {
for my $flavour ( @{ delete $hash{ $key } } ) {
push @{ $hash{ $flavour } }, $key;
}
}

print Dumper \%hash;
'
$VAR1 = {
'4' => [
'Strawberry',
'Pistachio'
],
'1' => [
'Chocolate',
'Vanilla',
'Rocky Road'
],
'3' => [
'Cookie Dough',
'Chocolate'
],
'2' => [
'Strawberry',
'Vanilla',
'Pistachio'
]
};

$VAR1 = {
'Chocolate' => [
'1',
'3'
],
'Cookie Dough' => [
'3'
],
'Strawberry' => [
'4',
'2'
],
'Rocky Road' => [
'1'
],
'Pistachio' => [
'4',
'2'
],
'Vanilla' => [
'1',
'2'
]
};



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
mlwollman@gmail.com
Guest
Posts: n/a
 
      10-04-2006
Thank You, Bob. That worked perfectly! Much appreciated.
Matt

Bob Walton wrote:
> (E-Mail Removed) wrote:
> ...
> > I have a hash with key value pairs like:
> > 1 => Chocolate,Vanilla,Rocky Road
> > 2 => Strawberry,Vanilla, Pistachio
> > 3 => Cookie Dough,Chocolate
> > 4 => Strawberry,Pistachio
> >
> > And I need to transform it to:
> > Chocolate => 1,3
> > Vanilla => 1,2
> > Rocky Road => 1
> > Strawberry => 2,4
> > Pistachio =>2,4
> > Cookie Dough => 3
> >
> > What's a good, simple way to do that?
> >
> > I thought about using while each and changing the value to an array and
> > foreach array element make a new has with the array element as a key
> > and the old key join() any existing values, I think. I'm pretty
> > confused now.

> ...
> > Matt
> >

>
> Here is one way, which is pretty much what you described, except I
> elected to use strings rather than arrays since I think you said you
> wanted strings:
>
> use warnings;
> use strict;
> use Data:umper;
> my %h; #original hash
> $h{1}='Chocolate,Vanilla,Rocky Road';
> $h{2}='Strawberry,Vanilla,Pistachio';
> $h{3}='Cookie Dough,Chocolate';
> $h{4}='Strawberry,Pistachio';
> my %h1; #flavors hash
> for(sort keys %h){
> my @v=split /,/,$h{$_}; #separate flavors
> for my $v(@v){
> $h1{$v}.="$_,"; #add number to flavor
> }
> }
> for(keys %h1){
> $h1{$_}=~s/,$//; #get rid of trailing commas
> }
> print Dumper(\%h1);
>
> --
> Bob Walton
> Email: http://bwalton.com/cgi-bin/emailbob.pl


 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      10-04-2006
(E-Mail Removed) wrote:
> John W. Krahn wrote:
>>
>>for my $key ( keys %hash ) {
>> for my $flavour ( @{ delete $hash{ $key } } ) {
>> push @{ $hash{ $flavour } }, $key;
>> }
>> }

>
> If I recall correctly, it isn't a good idea to delete
> and add keys to a hash while iterating over it.


"for my $key ( keys %hash )" creates a list of the hash keys in memory and any
modifications to %hash inside the loop won't affect the contents of that list.

perldoc -f delete


John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      10-04-2006
Bob Walton wrote:
>
> Here is one way, which is pretty much what you described, except I
> elected to use strings rather than arrays since I think you said you
> wanted strings:
>
> use warnings;
> use strict;
> use Data:umper;
> my %h; #original hash
> $h{1}='Chocolate,Vanilla,Rocky Road';
> $h{2}='Strawberry,Vanilla,Pistachio';
> $h{3}='Cookie Dough,Chocolate';
> $h{4}='Strawberry,Pistachio';
> my %h1; #flavors hash
> for(sort keys %h){
> my @v=split /,/,$h{$_}; #separate flavors
> for my $v(@v){
> $h1{$v}.="$_,"; #add number to flavor
> }
> }
> for(keys %h1){
> $h1{$_}=~s/,$//; #get rid of trailing commas
> }
> print Dumper(\%h1);


Another way to do it:

$ perl -le'
use Data:umper;
my %hash = (
1 => "Chocolate,Vanilla,Rocky Road",
2 => "Strawberry,Vanilla, Pistachio",
3 => "Cookie Dough,Chocolate",
4 => "Strawberry,Pistachio",
);
print Dumper \%hash;
for my $key ( keys %hash ) {
for my $flavour ( split /\s*,\s*/, delete $hash{ $key } ) {
push @{ $hash{ $flavour } }, $key;
}
}
$_ = join ",", @$_ for values %hash;
print Dumper \%hash;
'
$VAR1 = {
'4' => 'Strawberry,Pistachio',
'1' => 'Chocolate,Vanilla,Rocky Road',
'3' => 'Cookie Dough,Chocolate',
'2' => 'Strawberry,Vanilla, Pistachio'
};

$VAR1 = {
'Chocolate' => '1,3',
'Cookie Dough' => '3',
'Strawberry' => '4,2',
'Rocky Road' => '1',
'Pistachio' => '4,2',
'Vanilla' => '1,2'
};



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
 
Reply With Quote
 
Keith Keller
Guest
Posts: n/a
 
      10-04-2006
On 2006-10-04, John W. Krahn <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:
>> John W. Krahn wrote:
>>>
>>>for my $key ( keys %hash ) {
>>> for my $flavour ( @{ delete $hash{ $key } } ) {
>>> push @{ $hash{ $flavour } }, $key;
>>> }
>>> }

>>
>> If I recall correctly, it isn't a good idea to delete
>> and add keys to a hash while iterating over it.

>
> "for my $key ( keys %hash )" creates a list of the hash keys in memory and any
> modifications to %hash inside the loop won't affect the contents of that list.
>
> perldoc -f delete


While the actual for loop is documented in perldoc -f delete, the
creating a new list in memory aspect is more explicitly documented in
perldoc -f keys.

--keith

--
http://www.velocityreviews.com/forums/(E-Mail Removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://www.therockgarden.ca/aolsfaq.txt
see X- headers for PGP signature information

 
Reply With Quote
 
attn.steven.kuo@gmail.com
Guest
Posts: n/a
 
      10-04-2006
John W. Krahn wrote:
> (E-Mail Removed) wrote:


(snipped)

> >
> > If I recall correctly, it isn't a good idea to delete
> > and add keys to a hash while iterating over it.

>
> "for my $key ( keys %hash )" creates a list of the hash keys in memory and any
> modifications to %hash inside the loop won't affect the contents of that list.
>
> perldoc -f delete



Sorry, my recollection was indeed faulty.
I was thinking of the 'each' function used
to iterate over a hash.

--
Regards,
Steven

 
Reply With Quote
 
Mirco Wahab
Guest
Posts: n/a
 
      10-04-2006
Thus spoke Michele Dondi (on 2006-10-04 11:40):
> It's up to you to modify accordingly to your actual
> needs.
>
> my %rev;
> for my $k (keys %hash) {
> push @{ $rev{$_} }, $k for split /,/, $hash{$k};
> }
>


Hi Michele, to re-stringify the numbers array *is* just
major part of the fun

BTW: somebody *had* eventually to come up with it ...

my %h=(1 => 'Chocolate,Vanilla,Rocky Road',
2 => 'Strawberry,Vanilla, Pistachio',
3 => 'Cookie Dough,Chocolate',
4 => 'Strawberry,Pistachio');

my %r;

(($_=join '',%h)=~s/\s//g),s/(\d)([^\d]+)/ $r{$_}.=','x!!defined($r{$_}).$1for(split',',$2)/eg;

)

Regards

M.
 
Reply With Quote
 
Mirco Wahab
Guest
Posts: n/a
 
      10-04-2006
Thus spoke Michele Dondi (on 2006-10-04 12:49):
> On Wed, 04 Oct 2006 12:23:15 +0200, Mirco Wahab
> <(E-Mail Removed)> wrote:
>
>>> push @{ $rev{$_} }, $k for split /,/, $hash{$k};

>> re-stringify the numbers array

>
> It's not that hard to do so in the first place:
>
> $rev{$_} .= defined $rev{$_} ? ",$k" : $k
> for split /,/, $hash{$k};


Aehmm, you didn't pull the
leading \s+ from keys, eg. ' Pistachio'.

Why did you choose the explicit form of:

$rev{$_} .= ','x defined $rev{$_} . $k

I guess it's not always ok to expect that
'defined' gets evaluated to 0/1 !?

Regards

Mirco


BTW. some kind of a perlgolf version
anybody - for learning purpose? (the
hash has to be %h):

@_=%h;%h=(),($_="@_")
=~s/\s//g,s/(\d+)
([^\d]+)/$h{$_}
.=','x defined
($h{$_}).$1
for(split
',',$2)
/egx
;
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
Spliting hash using map! Ne Scripter Ruby 5 10-12-2009 01:48 PM
Hash#select returns an array but Hash#reject returns a hash... Srijayanth Sridhar Ruby 19 07-02-2008 12:49 PM
hash.keys and hash.values Mage Ruby 14 08-15-2006 08:44 PM
Hash#values and Hash#keys order Alex Fenton Ruby 1 04-15-2006 05:45 AM



Advertisments