in reply to Possible for Map to create Hash of Hash?

> $hash{(split)[0]}{(split)[1]} = 1 foreach <>;

> How can I achieve a similar result using map?

not "really", to do so you would need to use map in void context in order to act like foreach!

DB<163> map { ($a,$b)=split /\s+/; $hash{$a}{$b}=1 } <I>; => (1, 1, 1, 1) DB<164> \%hash => { Canberra => { 12 => 1, 18 => 1 }, Sydney => { 12 => 1, 14 => 1 } + }

(Please note that you are calling split twice, I avoided this by setting $a and $b and have full control over the delimiter.)

You can't have map returning nested hashes assigned to a top-level hash, otherwise entries from different lines would collide (2 x Sidney, 2 x Canberra) and be overwritten:

 %hash = map { entry1 => { entry2 => 1} } <> # collisions of entry1

Another concise way to do it, involving a "real" map and avoiding named variables:

DB<143> $hash{$_->[0]}{$_->[1]} = 1 for map { [split /\s+/] } <I> => "" DB<144> \%hash => { Canberra => { 12 => 1, 18 => 1 }, Sydney => { 12 => 1, 14 => 1 } + }

Of course creating an anonymous array is not optimal...

Cheers Rolf

( addicted to the Perl Programming Language)

Replies are listed 'Best First'.
Re^2: Possible for Map to create Hash of Hash?
by konnjuta (Acolyte) on May 11, 2013 at 12:15 UTC
    Thanks Rolf. This answered what I was trying to do achieve with map. I was hoping to be able to declare and initiate %hash in one line but couldn't get it to work because of the collision and couldn't be sure if it was possible.
    You can't have map returning nested hashes assigned to a top-level ha +sh, otherwise entries from different lines would collide (2 x Sidney, + 2 x Canberra) my %hash = map { entry1 => { entry2 => 1} } <> # collisions of entry1
      > couldn't be sure if it was possible.

      Well, I think the point is that map isn't primarily meant to operate on hashes, it takes a list and returns a list.

      LIST = map {BLOCK} LIST

      But assigning a list to a hash can result in collisions

      DB<166> %hash = (Canberra => { 12 => 1}, Canberra => { 18 => 1} ) => ("Canberra", { 18 => 1 })

      You could however design a sub join_deep , such that:

      DB<178> sub join_deep { my %hash; while ( my ($a,$b) = splice @_,0,2 ) { $hash{$a}= { %{$hash{$a}}, %$b } } return %hash; } DB<179> %h =join_deep (Canberra => { 12 => 1}, Canberra => { 18 => 1 +} ) => ("Canberra", { 12 => 1, 18 => 1 })

      But frankly, I don't see the need for such abstraction.

      Cheers Rolf

      ( addicted to the Perl Programming Language) couldn't be sure if it was possible.