Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

A hint about using map

by doom (Deacon)
on Apr 05, 2005 at 23:17 UTC ( [id://445124]=note: print w/replies, xml ) Need Help??


in reply to Turning foreach into map?

One of the things you always want to do with map is to use it to do a transformation on a list of strings.

At some point you're guaranteed to try something like this, but it won't work:

# WRONG @new_list_wrong = map{ s/that idiot/our esteemed leader/ } @list;
This is because s/// returns the *count* of the changes, rather than the changed string (most people agree this is a DWIM violation: this is an area where Larry blew it).

What actually works is something like this:

@new_list_right = map{ s/that idiot/our esteemed leader/; $_ } @list;

There's still another gotcha here though, in that if you look at the original @list after doing this, you'll find that it was transformed in exactly the same way as the new list. Each item in the @list array is aliased to $_, so it can be changed by running map on it. (Of course, you knew this. But you'll still get bitten by it on occasion.)

Weirdly enough, the m// operator doesn't have the same problem as s/// does: m// does pretty much what you'd expect in list context:

# yet another way to strip leading and trailing whitespace: @cleaned_list = map{ m/^\s*?(\w.*?)\s*?$/ } @list;

Trivia: perl is well known for having ripped off features form shell and awk, but map was lifted from lisp.

Replies are listed 'Best First'.
Re: A hint about using map
by merlyn (Sage) on Apr 05, 2005 at 23:29 UTC
    most people agree this is a DWIM violation: this is an area where Larry blew it
    It may not be a DWIM for you, but it's a DWLM (do what Larry means), and that's the only meaning that matters. In fact, I don't think it would look right for it to return the changed string. I like that I can use it as:
    if (s/foo/bar/) { # yes, I replaced foo with bar ... }
    So, it certainly DWIMs for me. Apparently, I'm not one of "most" in your sentence. However, a lot of people have learned from my books, so I suspect the number who understand it the the way I do would be a large portion of your minority.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      most people agree this is a DWIM violation: this is an area where Larry blew it
      It may not be a DWIM for you, but it's a DWLM (do what Larry means), and that's the only meaning that matters. In fact, I don't think it would look right for it to return the changed string. I like that I can use it as:
      if (s/foo/bar/) { # yes, I replaced foo with bar ... }
      So, it certainly DWIMs for me.
      Right, that's a point, but the way I look at it it would still work even if s/// was returning the changed string (except, of course, when the returned string was something like zero or an empty string).

      So the actual behavior does a slightly better job of DWIM in one case, and a worse job in another case... (and now that I think of it, why not return the string in list context and the count in scalar. Wouldn't that cover both bases?).

      Update: actually, there's another problem I haven't thought about -- if you're doing a map{ s///; $_ } you've got the string passed through map even if there's no match. If you had s/// return the string *only* if it were changed, then you could do an if(s///) with it (usually) but you'd probably end up a sticking a $_ on the end of your map blocks anyway, just to get the string passed through in the no match condition.

      s/where Larry blew it/where Larry's brilliance is more difficult to perceive/

        Right, that's a point, but the way I look at it it would still work even if s/// was returning the changed string (except, of course, when the returned string was something like zero or an empty string).
        Really? Then what should s/// return if *no* substitutions took place? undef? That would make
        @new_list = map {s/foo/bar/} @old_list;
        fail to do the right thing most of the time as well - it would only work if the old list only contain strings that would be affected by s///. You would still need to write that as:
        @new_list = map {s/foo/bar/; $_} @old_list;
        most of the time.
Re: A hint about using map
by jdporter (Paladin) on Apr 06, 2005 at 03:34 UTC
    One of the things you always want to do with map is to use it to do a transformation on a list of strings.
    Huh?
    @findings = map { $_->{$x} ? [ $_->{$y}, keys %$_ ] : () } @hashrefs;
    Here I'm slinging just references and numbers. And using the map to do a greppy thing at the same time.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2024-04-18 13:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found