104

While processing a list using map(), I want to access index of the item while inside lambda. How can I do that?

For example

ranked_users = ['jon','bob','jane','alice','chris']
user_details = map(lambda x: {'name':x, 'rank':?}, ranked_users)

How can I get rank of each user in above example?

Jayesh
  • 51,787
  • 22
  • 76
  • 99

4 Answers4

140

Use enumerate:

In [3]: user_details = [{'name':x, 'rank':i} for i,x in enumerate(ranked_users)] 

In [4]: user_details
Out[4]: 
[{'name': 'jon', 'rank': 0},
 {'name': 'bob', 'rank': 1},
 {'name': 'jane', 'rank': 2},
 {'name': 'alice', 'rank': 3},
 {'name': 'chris', 'rank': 4}]

PS. My first answer was

user_details = map(lambda (i,x): {'name':x, 'rank':i}, enumerate(ranked_users))

I'd strongly recommend using a list comprehension or generator expression over map and lambda whenever possible. List comprehensions are more readable, and tend to be faster to boot.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 3
    Shouldn't lambda's parameters be without parentheses? – dheerosaur Mar 25 '11 at 13:16
  • 3
    @dheerosaur Not in this case since the next() operation on enumerate returns a tuple. This lambda is equivalent to def foo((i,x)) – Rod Mar 25 '11 at 13:20
  • 1
    @dheerosaur: Actually, the parentheses are mandatory. `enumerate` generates tuples (a single object). – unutbu Mar 25 '11 at 13:21
  • @Rod, @unutbu: Got it. So, `lambda`s can't unpack tuples as list comprehensions do. – dheerosaur Mar 25 '11 at 13:32
  • 4
    @dheerosaur: Yes, lambdas do unpack differently than list comprehensions (in Python2). Note that in Python3, lambdas refuse to unpack at all: See http://diveintopython3.org/porting-code-to-python-3-with-2to3.html#tuple_params. – unutbu Mar 25 '11 at 14:10
  • If you don't pass a `lamdba` in, but instead use a `def something(index, character)`, this doesn't appear to work. Is there a way of doing this? – Jimmyt1988 Jun 13 '22 at 23:03
13

Alternatively you could use a list comprehension rather than map() and lambda.

ranked_users = ['jon','bob','jane','alice','chris']
user_details = [{'name' : x, 'rank' : ranked_users.index(x)} for x in ranked_users]

Output:

[{'name': 'jon', 'rank': 0}, {'name': 'bob', 'rank': 1}, {'name': 'jane', 'rank': 2}, {'name': 'alice', 'rank': 3}, {'name': 'chris', 'rank': 4}]

List comprehensions are very powerful and are also faster than a combination of map and lambda.

Community
  • 1
  • 1
Prydie
  • 1,807
  • 1
  • 20
  • 30
  • 11
    `list.index()` is only appropriate if all members of `ranked_users` are unique. Given `ranked_users = ['chris','chris']` `user_details` outputs `[{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 0}]` where it should be `[{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 1}]`. – thisgeek Nov 25 '12 at 15:51
  • It would only make sense (given this data) for the members to be unique though… – Prydie Nov 29 '12 at 11:39
  • Sure. Your answer fits the example. I just thought it would be a good idea to state the uniqueness caveat for anyone who comes across this post. – thisgeek Nov 29 '12 at 18:27
  • using index function call on ranked_users list is overengineered little bit. Python for expression iterates over objects in datastructure – cheshire cat Aug 16 '19 at 17:10
12

In my opinion the question was about map function and preferred answer is partly correct due to syntax error caused by putting tuple argument to lambda lambda (i,x)

idea of enumerate is nice and proper solution would be:

map(lambda x: {'name':x[1], 'rank':x[0]}, enumerate(ranked_users))

and some timing to compare speed with comprehension:

def with_map():
    ranked_users = range(10 ** 6)
    list(map(lambda x: {'name': x[1], 'rank': x[0]}, enumerate(ranked_users)))

def by_comprehension():
    ranked_users = range(10 ** 6)
    [{'name': x, 'rank': i} for i, x in enumerate(ranked_users)]

from timeit import timeit
time_with_map = timeit(with_map, number=10)
time_with_comprehension = timeit(by_comprehension, number=10)

print('list comprehension is about %.2f x faster than map in this test case' % (time_with_map/time_with_comprehension))

test result: list comprehension is about 1.31 x faster than map in this test case

cheshire cat
  • 181
  • 1
  • 5
6

Actually here is a more elegant, verbose solution than using an enumerate tuple in the map (because of tuple indexing). Map can take more iterables as arguments so let's use it.

map(lambda user, user_id: (user_id, user), ranked_users, range(ranked_users.__len__()))
xbalaj
  • 977
  • 1
  • 8
  • 14