Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Possible for Map to create Hash of Hash?

by konnjuta (Acolyte)
on May 11, 2013 at 10:47 UTC ( #1033095=perlquestion: print w/ replies, xml ) Need Help??
konnjuta has asked for the wisdom of the Perl Monks concerning the following question:

Suppose I have the following input:
STORE PRODUCT_ID ==================== Sydney 12 Sydney 14 Canberra 12 Canberra 18
To create a hash that will allow me to determine if a store has a product I can use:
my %hash; $hash{(split)[0]}{(split)[1]} = 1 foreach <>;
How can I achieve a similar result using map?

Comment on Possible for Map to create Hash of Hash?
Select or Download Code
Re: Possible for Map to create Hash of Hash?
by Anonymous Monk on May 11, 2013 at 10:48 UTC

    Can I achieve a similar result using map?

    sure, but why do you want to?

      I was fascinated with the Schwartzian transform and would like to learn more about list manipulation using functions like map
        untested
        my %hash = map { my @explicit = split //, $_; $explicit[0] => { $explicit[1] => 1 }; } <>;
Re: Possible for Map to create Hash of Hash?
by LanX (Canon) on May 11, 2013 at 11:45 UTC
    > $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)

      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.

Re: Possible for Map to create Hash of Hash?
by vsespb (Hermit) on May 11, 2013 at 13:50 UTC
      What's the point of splitting $store and $product only to join them again?

        It's joined again with "\034" (by default)

        You will be able to access this hash from other code using $h{$store,$product}. It's easier to write than $h{"$store $product"}

        If, later, you decide that store can have spaces in its name, you will rewrite your first split code, but you won't have to rewrite $h{$store,$product} in other places.

        Anyway, you can ask topic starter why he need split, while he just needs to

        to determine if a store has a product
      $h{$store, $product}=1;
      This is flaky to say the least. I assume you meant
      $h{"$store,$product"}=1;
      so atleast it'd be possible to pick them apart later on.

      Even so, it will only be a matter of time until a store pops up with a comma in its name and you'll have to start rethinking the whole thing. Maybe try two or three different delimiters before rewriting to use a better suited data structure.

      Like, say, a hash of hashes ;-)

      -- Time flies when you don't know what you're doing
        I assume you meant $h{"$store,$product"}=1;
        No. Re-read my posting. Also, click the link in my posting and read perldoc article.
Re: Possible for Map to create Hash of Hash?
by sundialsvc4 (Abbot) on May 12, 2013 at 15:06 UTC

    Several of the solutions batted-about here so far suffer in my humble from “the cardinal sin of brevity.”   Yes, they are short, but they are not clear.   The code, whatever it is, should be abundantly clear and also readily maintainable, even as the requirements are known to change and evolve over time.   I deal mostly with existing systems, and it is quite painful to watch “clever” code reacting like a bowl of fragile gelatin to what should have been an ordinary and small evolution.   I never care for “how few lines it takes,” and assume that there are always a few more microseconds to spare.   (Granted, I do not deal in über-performance situations, at least not in Perl.)   Please, write it in the most obvious way possible, and add plenty of comments.

      It's called functional programming and the OP explicitly wanted to know if it's feasible with map.

      So if it's not clear enough for you, better switch to BASIC.

      Please don't try to bla bla us down to your "standards"!

      It's almost always useful to explore other ways to express yourself, be it in english or in Perl. Whether or not it is wise to use those newfound expressions in public or production is an entirely different discussion.

      So, it turns out that map() seems like an awkward way to create a Hash of Hashes. That's fine. Simply seeing map() used in different ways can help to unlock its usefulness, by seeing it put to use. It certainly did for me.

      Earlier today I learned about a new and bizarre way to use glob() for calculating permutations. The code was nearly incomprehensible and I'd never actually use it for anything but new and interesting ideas were sparked.

      -- Time flies when you don't know what you're doing

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1033095]
Approved by Corion
Front-paged by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (11)
As of 2014-10-20 22:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (92 votes), past polls