Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Simplifying for loop and applying multiple push function

by jesuashok (Curate)
on Dec 14, 2005 at 20:42 UTC ( [id://516759]=perlquestion: print w/replies, xml ) Need Help??

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

Hi perl lovers

how to simplify the following code

+ %hash = ( 1 => 'one' , 2 => 'two' , 3 => 'three' ); + + foreach ( keys %hash ) { push @one , $hash{$_}; push @two, $_; }
I want the above for to be in single line and consider the performance also.

"Keep pouring your ideas"

Replies are listed 'Best First'.
Re: Simplifying for loop and applying multiple push function
by Roy Johnson (Monsignor) on Dec 14, 2005 at 20:53 UTC
    You're not going to be able to do it sensibly in one line. You can get rid of the loop and do it in two statements, though:
    push @one, values %hash; push @two, keys %hash;

    Caution: Contents may have been coded under pressure.

      Great solution! And if anyone else was wondering, yes, these will both be properly ordered:

      From keys:

      The keys are returned in an apparently random order. The act +ual random order is subject to change in future versions of perl +, but it is guaranteed to be the same order as either the "val +ues" or "each" function produces (given that the hash has not bee +n modified).

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        That's only the same if @one and @two started out empty.

        Caution: Contents may have been coded under pressure.
Re: Simplifying for loop and applying multiple push function
by davido (Cardinal) on Dec 14, 2005 at 21:16 UTC

    Just because someone said it can't be done in one line, I had to try:

    use warnings; use strict; my %hash = ( 1 => 'one' , 2 => 'two' , 3 => 'three' ); # Here is the one line! my( @one ) = @hash{ my( @two ) = keys %hash }; # This line is just to demonstrate it worked. print map { "$two[$_] => $one[$_]\n" } 0 .. $#two;

    Turns out you can do it in one with a slice. Roy_Johnson's approach deserves a ++ though, since it is actually legible. :)


    Dave

Re: Simplifying for loop and applying multiple push function
by BrowserUk (Patriarch) on Dec 14, 2005 at 22:24 UTC

    In one line with no pushing or cheating :)

    @hash{ 'a'..'z' } = 1 .. 26;; 1 while ( $one[@one], $two[@two] ) = each %hash;; print "@one\n@two";; r a x d j y u k h g f t i e n v m s l c p q b z o 18 1 24 4 10 25 21 11 8 7 6 20 9 5 14 22 13 19 12 3 16 17 2 26 15

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Simplifying for loop and applying multiple push function
by GrandFather (Saint) on Dec 14, 2005 at 21:57 UTC

    or a sneeky version:

    --$| ? push @one, $_ : push @two, $_ foreach %hash;

    DWIM is Perl's answer to Gödel

      If you were going to be sneaky about it, surely you'd write it like so:

      push @{--$| ? \@one : \@two}, $_ for %hash;

      P.S. Is there some unspoken mission to use --$| for everything?

Re: Simplifying for loop and applying multiple push function
by GrandFather (Saint) on Dec 14, 2005 at 21:46 UTC

    As one line using the comma operator:

    use strict; use warnings; my %hash = ( 1 => 'one' , 2 => 'two' , 3 => 'three' ); my (@one, @two); (push @one , $hash{$_}), push @two, $_ foreach ( keys %hash ); print "@one\n@two";

    Prints:

    one three two 1 3 2

    DWIM is Perl's answer to Gödel
Re: Simplifying for loop and applying multiple push function
by serf (Chaplain) on Dec 14, 2005 at 21:01 UTC
    use strict; use warnings; my %hash = ( 1 => 'one', 2 => 'two', 3 => 'three' ); my(@one,@two); while ( my ( $key, $val ) = each %hash ) { push @one, $val; push @two, $key; }
Re: Simplifying for loop and applying multiple push function
by GrandFather (Saint) on Dec 14, 2005 at 22:22 UTC

    Benchmark time :)

    Results:

    Rate sneekyDuff BUK sneekyGF orig GF roy + VS davido sneekyDuff 55138/s -- -3% -20% -40% -40% -52% - +54% -55% BUK 57031/s 3% -- -18% -38% -38% -51% - +52% -53% sneekyGF 69161/s 25% 21% -- -25% -25% -40% - +42% -43% orig 92056/s 67% 61% 33% -- -0% -21% - +23% -25% GF 92056/s 67% 61% 33% 0% -- -21% - +23% -25% roy 115883/s 110% 103% 68% 26% 26% -- +-3% -5% VS 119184/s 116% 109% 72% 29% 29% 3% + -- -2% davido 122008/s 121% 114% 76% 33% 33% 5% + 2% --

    Being sneeky doesn't pay :)

    Update for BrowserUK version


    DWIM is Perl's answer to Gödel
Re: Simplifying for loop and applying multiple push function
by qq (Hermit) on Dec 14, 2005 at 22:09 UTC
    my %hash = ( 1 => 'one' , 2 => 'two' , 3 => 'three' ); no strict; map { push @{ ++$i % 2 ? 'one' : 'two'}, $_ } %hash; print "@one\n"; print "@two\n";

    Another one-line attempt. But maybe it should count as two...

Re: Simplifying for loop and applying multiple push function
by NetWallah (Canon) on Dec 15, 2005 at 04:59 UTC
    I would question choice of the data structure used.

    Given just the context in the OP's question, I would structure %hash as an array, and the problem practically solves itself.

    my @arr = qw(one two three); my @one=@arr; my @two = 1..$#one+1;
    This, ofcourse, assumes the indices (or keys) are sequential, numeric. If this is NOT the case, it is still more convenient to look at the %hash as an array of tuples, and code it as an AOA, since there seems to be an implied requirement to retrieve elements in a particular order.

         You're just jealous cause the voices are only talking to me.

         No trees were killed in the sending of this message.    However, a large number of electrons were terribly inconvenienced.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (8)
As of 2024-03-28 17:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found