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

Back to Remedial Perl for Me: map{} function

by jreades (Friar)
on Dec 15, 2000 at 20:10 UTC ( #46832=perlquestion: print w/replies, xml ) Need Help??

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

While understanding what map{} is supposed to do, I seem to be consistently unable to use it correctly... which suggests that, on some level I really don't know what it actually does.

As I understand it, map{} applies some function (defined within the BLOCK) to each element of an array and the result is passed to the left.

So, you could, for instance, write a for loop without using a for simply by writing:

my @array = (1, 2, 3, 4, 5); my @adjusted_array = map { $_ * 10 } @array; print (join ',', @adjusted_array);

But what about more complicated statements?

I make it about as far as loading a hash from an array that I've split before it all starts to look like a monkey hitting the keys largely at random.

my @array = ('one-1', 'two-2', 'three-3', 'four-4', 'five-5'); my %hash = map { split /-/ } @array; print (join ',', keys %hash);

Why, for instance, could I not work this through even though it's clearly a mapping situation?

if ($access) { foreach (@{$access}) { $set{$_->[0]} = $_->[1]; } }

I guess what I'm seeking is the wisdom to understand how map operates within the BLOCK since most mentions of the map{} function are either cryptic or basic and I fall somewhere in between.


Replies are listed 'Best First'.
Re: Back to Remedial Perl for Me: map{} function
by merlyn (Sage) on Dec 15, 2000 at 20:13 UTC
    In that last one, you aren't wanting one list from another list. You want an action for each element in the list, and that's clearly appropriate for a foreach. You're doing well. map is when you want one list turned into another list.

    -- Randal L. Schwartz, Perl hacker

      Sorry, merlyn, but the second example *is* turning a list into another list. map is very capable of mapping 1-to-n relations, ie, every element on the right will produce more than one element on the right.

      If I read your statement correctly ( and I may not have ), the first use of map isn't correct

      my @first = qw/ one-1 two-2 three-3/; my %hash = map { split /-/ } @first; # Which works for me btw print map { "$_ => $hash{$_}\n" } keys %hash;
      But this usage is correct
      my @first = qw/ one-1 two-2 three-3/; my @second = map { split /-/ } @first; my %hash = @second; # Legal code, isn't it? print map { "$_ => $hash{$_}\n" } keys %hash;

      How else is map supposed to make @first into @second except by performing an action on every element of @first?

      I am not arguing that a foreach wouldn't be appropriate here. If that is what works, by all means use it. But if I am not supposed to use map when I want an action on every element of an array, doesn't it make more sense to say

      @second = @first;
      because that seems to be the only option you have left me with this statement.

      Would you be kind enough to expand on your answer so I can figure out what I missed?


        I wasn't commenting on either of those. I was commenting on the original poster's last example:
        if ($access) { foreach (@{$access}) { $set{$_->[0]} = $_->[1]; } }
        That's just fine as it is. No need for a map. In fact, a map would be difficult here, unless we presume %set is already empty before we get here.

        -- Randal L. Schwartz, Perl hacker

        Out of interest, why does this (both examples) print:
        one => 1 three => 3 two => 2
        and not:
        one => 1 two => 2 three => 3
Re: Back to Remedial Perl for Me: map{} function
by Dominus (Parson) on Dec 15, 2000 at 21:14 UTC
    Says jreades:
    if ($access) { foreach (@{$access}) { $set{$_->[0]} = $_->[1]; } }
    If I understand this correctly, it seems to me that the map version you are looking for is:
    %set = map {($_->[0], $_->[1])} @$access;
    I have notes somewhere for a program that would generate this sort of thing automatically, given an example of the input and an example of the output, but I never got it completely figured out.

Re: Back to Remedial Perl for Me: map{} function
by ichimunki (Priest) on Dec 16, 2000 at 00:31 UTC
    I've been trying to grok the perlfunc:map function too-- and this was encouragement to dig deeper, so I decided to play with it. I tried rewriting it using lower-level functions. I came up with the following, which in all the minimal testing I did seemed to reproduce the results of map. I even used a $function which was more complex and returned multiple elements for some items in the original list. This helped me get a way of thinking about the command (and hopefully it's a good way to think about it), so I thought I'd share.
    use strict; my @start_list = (qw/ one two three four five six /); my $function = sub { uc }; my @end_list = fake_map( $function, @start_list ); #equivalent to @end_list = map { &$function } @start_list; my %end_hash = fake_map( $function, @start_list ); #equivalent to %end_hash = map { &$function } @start_list; print (join (' ', @end_list, "\n") ); foreach (keys %end_hash) { print "hash{'$_'} = $end_hash{$_}\n"; } sub fake_map { my $func = shift; my @instack = @_; my @outstack = (); foreach (@instack) { push (@outstack, &$func); } return @outstack; }
Re: Back to Remedial Perl for Me: map{} function
by dchetlin (Friar) on Dec 16, 2000 at 01:33 UTC
    A note on efficiency:

    `map EXPR, LIST' is in general quite a bit faster than `map BLOCK LIST', so you should probably try to use EXPRs rather than BLOCKs whenever possible in a map.

    For instance, here are your first examples recoded as EXPRs:

    my @adjusted_array = map $_ * 10, @array;

    my %hash = map split /-/, @array;

    Why is it faster? Using the BLOCK introduces a new scope, which adds some extra ops and time to start and finish. BLOCKs do give you extra power and flexibility, but try to use them only when necessary.


      Why is it faster?

      Because the optimizer is "broken". (:

              - tye (but my friends call me "Tye")
Re: Back to Remedial Perl for Me: map{} function
by Anonymous Monk on Dec 15, 2000 at 21:52 UTC

    Question for the monks:

    Isn't it true you could do something like this (even though it's probably not in keeping with the intent of map)?

    # a way to count the number of elements in a list my $count = 0; my @listOfThings = ('one', 'two', 'three'); map { ++$count } @listOfThings; print "There are $count things in your list of things.\n";

    This example completely ignores the fact that the elements in the list are assigned to $_. We could care less what was in those elements. All we want to do is to execute this block once for each element that is in the list.

        Of course...

        I just wanted to point out that you don't have to really do anything with the elements of @listOfThings if you don't want to; you can do something completely unrelated.

        As an aside, and you may call this trolling (or you may not), I just wanted to see what people would say about this sort of use of map. It's probably a Bad Idea. It would be really interesting to see if somebody could convince me it's a Good Idea. :-)

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2023-03-31 15:19 GMT
Find Nodes?
    Voting Booth?
    Which type of climate do you prefer to live in?

    Results (76 votes). Check out past polls.