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

Back to Remedial Perl for Me: map{} function

by jreades (Friar)
on Dec 15, 2000 at 20:10 UTC ( [id://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.

TIA

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?

      TIA
      mikfire

        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.

    -dlc

      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?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-23 16:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found