[Tutor] map, filter and lambda functions

Sheila King sheila@thinkspot.net
Wed, 22 Aug 2001 20:59:25 -0700

On Thu, 23 Aug 2001 01:01:58 +0100, "Allan Crooks"
<allan.crooks@btinternet.com>  wrote about Re: [Tutor] map, filter and
lambda functions:

:On 22 Aug 2001, at 16:16, Sheila King wrote:
:> Here's the new, shorter version:
:> checklist = string.split(filetext, "\n")
:> checklist = filter(lambda x: x != '', checklist)
:> checklist = map(lambda x: string.strip(x), checklist)
:> checklist = map(lambda x: string.upper(x), checklist)

:My opinion is, the best version is the one which makes you smile 
:more. :) Out of the two, I like the second one more.

Well, I really was asking for an outside opinion, and someone who knew a
bit more about optimizing the code.

:> Is there a way to do this without lambda functions, or are they
:> pretty much needed in this case?
:You don't need to put lambda functions, you can just provide 
:string.strip and string.upper without using lambda what-so-ever.

Are you sure that you can do this without lambda? I tried today, and
couldn't get it to work without lambda.

>>> mylist
['a', 'b', 'c', '']
>>> mylist = map(string.upper(x), mylist)
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in ?
    mylist = map(string.upper(x), mylist)
NameError: name 'x' is not defined
>>> mylist = map(string.upper(), mylist)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in ?
    mylist = map(string.upper(), mylist)
TypeError: upper() takes exactly 1 argument (0 given)

If I do it with no argument, it complains that it requires an argument.
If I put an argument there, it complains that it has never heard of that
variable before.

That's what prompted me to try the lambda functions. I figured, I could
thereby (essentially) declare the variable x before I used it.

:I would personally, however, write this:
:checklist = map (lambda x: x.strip().upper(), checklist)
:or, if Python 1.5.2 doesn't like that:

No, 1.5.2 requires the string module to do string functions.

:checklist = map (lambda x: string.upper(string.strip(x)), checklist)
:Which reduces it down to one line. But you might not want that.

Not too readable, IMO.

:You could also replace the lambda function that's used in filter with 
:"None". IIRC, that will only return objects which have a positive 
:truth value (in the case of strings, this would only be non-empty 

Hmm. That seems to work:

>>> mylist
['a', 'b', 'c', '']
>>> filter(None, mylist)
['a', 'b', 'c']

Now I'm curious as to *why* it works. 'None' doesn't strike me as a
function that returns a value. Although, it says in the documentation
somewhere, that None on map works as the identity function. This didn't
bother me, though. It seemed like "No map...gives you same thing you
started with."

:If you were really daring, you could put all that into one large 
:checklist = map (string.upper, map (string.strip, filter (None, 
:string.split(filetext, "\n"))))
:That *might* work, I can't be bothered to test it. :)

OK, two remarks on this:
First of all, does putting it all in one line make it run faster or more
efficiently? My intuition says, "No".

Secondly, it's definitely harder to follow. I would be very disinclined
to writing it like that. Having the code be compressed into a single
line really isn't that appealing.

:Use whatever version you are happiest with. I'd go with whatever 
:version is easier to understand when you read it, which, out of the 
:two you've given us, would be the second one.

That's an interesting remark. Until today, I wouldn't have found those
filter and map, or lambda functions easy to read and understand.
Something clicked today, and now I'm fine with them. But before, I would
have preferred the nested loop stuff I had originally.

Sheila King