Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Syntax explanation required

by ghosh123 (Monk)
on Jan 02, 2013 at 12:15 UTC ( [id://1011256]=perlquestion: print w/replies, xml ) Need Help??

ghosh123 has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monk,

I need to understand this following syntax which is collecting the unique keys from two hashes into one array.
The following code works fine, but I do not understand the meaning of the syntax, please explain me

my @uniq = keys %{ {%hash1, %hash2} };
Please explain me the syntax of the right hand side, how does this keys % { {%h1,%h2 } } thing work ??

Thanks.

Replies are listed 'Best First'.
Re: Syntax explanation required
by LanX (Saint) on Jan 02, 2013 at 12:35 UTC
    > my @uniq = keys %{ {%hash1, %hash2} };

    From inside out:

    - First the two hashes are flattened to lists, which are combined to a long list.

    - Building a new (anonymous) hashref will eliminate duplicated entries from that hash ¹

    - To be able to extract² the keys you still need to dereference this ano-hashref with %{..}.

    step by step:

    DB<111> %hash1= (a=>1,b=>2) => ("a", 1, "b", 2) DB<112> %hash2= (a=>1,c=>3) => ("a", 1, "c", 3) DB<113> (%hash1, %hash2) => ("a", 1, "b", 2, "c", 3, "a", 1) DB<115> + {%hash1, %hash2} => { a => 1, b => 2, c => 3 } DB<117> %{ {%hash1, %hash2} } => ("c", 3, "a", 1, "b", 2) DB<118> keys %{ {%hash1, %hash2} } => ("c", "a", "b")

    Cheers Rolf

    UPDATES:

    ¹) because repeated keys will be overwritten.

    ²) at least with older perl-versions, see Athanasius' remark

      Wonderful explanation by 'step-by-step'

      Thanks a lot !!!
Re: Syntax explanation required
by Athanasius (Archbishop) on Jan 02, 2013 at 13:10 UTC

    Hello ghosh123,

    LanX has explained the syntax of the expression, but you may be wondering, why create a hash reference only to immediately dereference it?

    A solution using a third, named hash is more straightforward:

    my %hash3 = (%hash1, %hash2); my @uniq = keys %hash3;

    But what happens if we want to eliminate the named hash? The obvious approach:

    my @uniq = keys (%hash1, %hash2);

    doesn’t work, because the Perl interpreter sees only a simple list. So it’s necessary to tell the interpreter to create a hash, but the only syntax for this that doesn’t involve another named hash is curly braces {}, which creates a hash as required but returns a reference to it. Hence the need for the more complicated syntax which creates the hash reference and then dereferences it.

    Actually, however, this isn’t necessary in Perl 5.14 or later, because keys can now also take a hash reference as its argument:

    #! perl use Modern::Perl; use Data::Dump; my %hash1 = (fred => 'wilma', barney => 'betty'); my %hash2 = (homer => 'marge', fred => 'wilma'); my @uniq = keys { %hash1, %hash2 }; dd @uniq;

    Output:

    23:05 >perl 464_SoPW.pl ("barney", "homer", "fred") 23:08 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Syntax explanation required
by eyepopslikeamosquito (Archbishop) on Jan 03, 2013 at 01:27 UTC

    Two alternative ways derived from: perldoc -q duplicate

    my %seen; my @uniq = grep { !$seen{$_}++ } keys(%hash1), keys(%hash2);

    use List::MoreUtils qw(uniq); my @uniq = uniq( keys(%hash1), keys(%hash2) );

      I was meditating about advising List::MoreUtils:uniq as a best practice, cause I thought it prevents any stringification problems.¹

      Unfortunately it doesn't! :(

      DB<125> $a=["A"] => ["A"] DB<126> $b=["B"] => ["B"] DB<127> @a=($a,"$a",$b,"$b") => (["A"], "ARRAY(0x96cb0f0)", ["B"], "ARRAY(0x96cfd80)") DB<128> @b= uniq @a => (["A"], ["B"])

      thats quite disappointing for an XS-module ...

      EDIT: Well at least it preserves order...

      Cheers Rolf

      ¹) I should explain, the problem with using hashes for set operations is that keys are stringified, that means working with anything which isn't a string or at least a scalar comes with a risk.

      Practically it's not possible to safely use a ref as a key because of the resulting string is irreversible.

      DB<130> $h{$a}=5 => 5 DB<131> %h => ("ARRAY(0x96d1f00)", 5)

      UPDATE:

      improved code example...

        Thank you all. Very helpful !!!
Re: Syntax explanation required
by sundialsvc4 (Abbot) on Jan 02, 2013 at 21:29 UTC

    And I would cordially augment Anathasius’s excellent response by making two observations:

    1. There’s More Than One Way To Do/Say It (TMTOWTDI™) ... and ...
    2. “At the end of the day,” the hands-down winner is:   the one that is the most clear, to the greatest number of human beings who will actually encounter it, either now or in the distant future.

    When you are writing source code, it frankly does not matter whether what you have written is “efficient,” much less “clever.”   (And in making that comment, I consciously and respectfully intend to steer the middle-ground against acknowledged valid ... [BrowserUK] ... edge-case exceptions ...)   What (typically) matters is that what you’ve written is drop-dead obvious ... and maintainable.   (You are not at the computational bleeding-edge and never will be.)   Even if the piece of source-code that you encountered works perfectly as-writ (as I presume it does), it triggered a show-stopper question from you that was sufficient to prompt a humble-petition to The Monks.   For that reason alone, it should be judged Insufficient.   It should, at the very least, be prefaced by a comment.

    Yeah, there is a “hard dollars” motivation for doing that.   The mere fact that it triggered a public comment titled “Syntax explanation required” classifies it as “very $$costly$$.”   Most of the time, there are many equally-valid ways to express your intentions to the digital computer, and so what really matters is how clear it is to your colleagues.

      What?
Re: Syntax explanation required
by Anonymous Monk on Jan 02, 2013 at 21:44 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-03-19 06:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found