3

I am learning python and was just fiddling with the lambda expressions and list comprehensions when I realized that:

>>> list(map(lambda x: x*x, [1,2]))

outputs >>> 1,4 but

>>> list(map(lambda (x): x*x, [1,2])) shows an error pointing at parenthesis around x

It appears that the lambda expression cannot have a parenthesis around its parameters list. (Checked in python 3.x)

I now want to ask that if I cannot add a parenthesis around the parameters in the lambda expression, then how can I process a tuple using a map and a lambda expression. for eg:

>>> records = [('bob', 35, 'manager'), ('sue', 40, 'developer')]
>>> list(map((lambda (name, age, job): age), records))

this statement shows a syntax error indicating the parenthesis before the name parameter. I then tried an expression without the parenthesis:

>>> list(map((lambda name, age, job: age), records))

But this statement also shows an error saying that lambda expression needs 3 arguments but only 1 was provided.

I get that the map function is pulling out an entire record tuple from records list and passing it to the lambda function, and the lambda function is taking this entire tuple record as an argument to the name parameter.

I want to know, How can I process a tuple in a lambda expression. Also please tell me why is it written so in the book (Learning python by Mark Lutz) that this works? Is it for python 2.x. I am new to python. Thanks in advance.

Gsbansal10
  • 303
  • 5
  • 12
  • 1
    Apparently, it works on my system which has 2.7 environment so book is not completely wrong – mad_ Nov 08 '18 at 18:17
  • An other way of doing the same: `list(map(lambda x: x[1], records))`. – Austin Nov 08 '18 at 18:19
  • @mad_ Thanks. I thought so for version 2.7 but had no means of checking the same. you cleared my doubt. I appreciate it. Thank you. – Gsbansal10 Nov 08 '18 at 20:35

3 Answers3

5

You can use the special unpacking syntax with lambdas in Python2 only. However, you can use itertools.starmap to accomplish the unpacking of each item in records as it is passed to the function under the hood in Python3:

import itertools
records = [('bob', 35, 'manager'), ('sue', 40, 'developer')]
print(list(itertools.starmap(lambda name, age, job: age, records)))

Output:

[35, 40]
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
4

The syntax you are attempting works in Python 2.x. It won't work in Python 3.

In Python 3, you can use positional indexing:

from operator import itemgetter

records = [('bob', 35, 'manager'), ('sue', 40, 'developer')]

ages1 = list(map(lambda x: x[1], records))   # [35, 40]
ages2 = list(map(itemgetter(1), records))    # [35, 40]

Better (more efficient, more readable) is to abandon lambda altogether. You can use a list comprehension with sequence unpacking:

ages3 = [age for _, age, _ in records]       # [35, 40]

You can even use zip if you don't mind a tuple:

_, ages4, _ = zip(*records)                  # (35, 40)

For a cleaner version of the last solution, you can use itertools.islice:

from itertools import islice

ages5 = next(islice(zip(*records), 1, 2))    # (35, 40)
jpp
  • 159,742
  • 34
  • 281
  • 339
  • 2
    Or just `ages3 = [age for _, age, _ in records]`. – Austin Nov 08 '18 at 18:22
  • @Austin, Agreed :). I left the other identifiers there for clarity. But in terms of design you're right, unused variables don't need to be named. – jpp Nov 08 '18 at 18:23
0

Why not just

list(map((lambda x:x[1]), records))
mad_
  • 8,121
  • 2
  • 25
  • 40