Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

map2 {} grep2 {} ...

by jozef (Sexton)
on Jul 14, 2011 at 11:46 UTC ( #914324=perlquestion: print w/ replies, xml ) Need Help??
jozef has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to have a possibility to use map or grep with value couples instead of just one single $_. It should make it possible to loop through a hash while having easy access to both key and value, or through an array but taking two elements at a time. For example:

%h = ( key1 => 123, key2 => 'acb', key3 => 5, ); # create second hash with only numeric values %h_numbers = grep2 { looks_like_number($_[1]) } %h; # prefix all values with "p" %h_prefixed = map2 { ($_[0], "p".$_[1]) } %h; @a = ( p1 => 111, p2 => 222, p3 => 333 ); # transforms array of ordered couples to array of single element hashe +s @a_hashed = map2 { +{ $_[0] => $_[1] } } @a;

What are the clever options to achieve this? Thank you!

Comment on map2 {} grep2 {} ...
Download Code
Re: map2 {} grep2 {} ...
by moritz (Cardinal) on Jul 14, 2011 at 12:09 UTC
      See List::MoreUtils, specifically pairwise (and natatime for the general case)

      Neither pairwise() nor natatime() come even close to doing what the OP has asked for.

Re: map2 {} grep2 {} ...
by Anonymous Monk on Jul 14, 2011 at 12:09 UTC
    Consider "each." Also consider a while loop that shifts the first variable off an array in the "while" part, then shifts the remainders off during the body of the loop (using "last unless" as needed).
Re: map2 {} grep2 {} ...
by Tux (Monsignor) on Jul 14, 2011 at 12:10 UTC
    %h_numbers = map { looks_like_number ($h{$_}) ? ($_, $h{$_}) : () } keys %h;

    %h_numbers = map { @$_ } grep { looks_like_numebr ($_->[1]) } map { [ $_, $h{$_} ] } keys %h;


    Enjoy, Have FUN! H.Merijn
Re: map2 {} grep2 {} ...
by BrowserUk (Pope) on Jul 14, 2011 at 12:13 UTC

    Define them yourself:

    sub map2(&@){ my $code = shift; map $code->( shift, shift ), 0 .. $#_/2 } sub grep2(&@){ my $code = shift; map{ my @pair = (shift,shift); $code->( @pair ) ? @pair : () } 0 .. $#_/2 }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Works like a charm! Thank you very much.

      An excellent suggestion.   Fav’d.   The best way to solve a problem is not just “a solution that works,” but, as here, “a solution that is abundantly clear.”   Something that gives you, not only the ability to do something, but a way to point out to your successor what you are doing and why you are doing it ... to capture the original designer’s intent.

Re: map2 {} grep2 {} ...
by JavaFan (Canon) on Jul 14, 2011 at 15:57 UTC
    Some solutions that don't require a special map or grep:
    %h_numbers = map {looks_like_number($h{$_}) ? ($_, $h{$_}) : ()} keys +%h; # Or %h_numbers = map {($_, $h{$_})} grep {looks_like_number($h{$_})} keys +%h; %h_prefixed = map {($_, "p".$h{$_})} keys %h; # Or %h_prefixed = %h; $_ = "p$_" for values %h_prefixed; # Both solutions below destroy @a; but you can make a copy first. while(my($x,$y) = splice @a, 0, 2) {push @a_hashed, {$x, $y}} # Or push @a_hashed, {shift @a, shift @a} while @a;
Re: map2 {} grep2 {} ...
by ikegami (Pope) on Jul 14, 2011 at 16:37 UTC
    You don't even use the key in
    my %h_prefixed = map2 { ($_[0], "p".$_[1]) } %h;
    You could do
    my %h_prefixed = %h; $_ = "p$_" for values %h_prefixed;

      He *did* use the keys -- to construct the new hash.

      And you also used the keys, when you constructed the new hash.

      But you also used the values at point -- and then again when you modified them.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re: map2 {} grep2 {} ...
by betterworld (Deacon) on Jul 14, 2011 at 17:30 UTC

    The solutions offered so far are very sophisticated, but I think the most stupid way is also the most readable:

    my %h_prefixed; my %h_numbers; while(my ($key, $val) = each %h) { $h_numbers{$key} = $val if looks_like_a_number($val); $h_prefixed{$key} = "p$val"; }

    And it's (probably) not even slower or anything.

    For a (maybe a bit) less readable solution, I'd like to offer the following:

    my %h_prefixed; @h_prefixed{keys %h} = map "p$_", values %h;
Re: map2 {} grep2 {} ...
by duelafn (Priest) on Jul 14, 2011 at 18:45 UTC

    I think it looks better if one makes use of $a and $b

    sub map2(&@) { my $f = shift; my @res; no strict 'refs'; my $caller = caller; local(*{$caller."::a"}) = \my $a; local(*{$caller."::b"}) = \my $b; if (defined(wantarray)) { push @res, $f->($a,$b) while ($a, $b) = splice @_, 0, 2; return @res; } else { $f->($a,$b) while ($a, $b) = splice @_, 0, 2; } } # ... %h_prefixed = map2 { ($a, "p$b") } %h; @a_hashed = map2 { +{ $a => $b } } @a;

    Good Day,
        Dean

Log In?
Username:
Password:

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

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

    For retirement, I am banking on:










    Results (92 votes), past polls