Abrufen des Index des Elements während der Verarbeitung einer Liste mithilfe der Karte in Python

74

Während der Verarbeitung einer Liste mit map () möchte ich in Lambda auf den Index des Elements zugreifen. Wie kann ich das machen?

Zum Beispiel

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

Wie kann ich den Rang jedes Benutzers im obigen Beispiel ermitteln?

Jayesh
quelle

Antworten:

107

Verwenden Sie Aufzählung :

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. Meine erste Antwort war

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

Ich würde dringend empfehlen, immer mapund lambdawann immer möglich ein Listenverständnis oder einen Generatorausdruck zu verwenden. Listenverständnisse sind besser lesbar und lassen sich in der Regel schneller starten.

unutbu
quelle
2
Sollten Lambdas Parameter nicht ohne Klammern stehen?
Dheerosaurier
1
@dheerosaur Nicht in diesem Fall, da die nächste () Operation bei der Aufzählung ein Tupel zurückgibt. Dieses Lambda entspricht def foo ((i, x))
Rod
1
@dheerosaur: Eigentlich sind die Klammern obligatorisch. enumerateerzeugt Tupel (ein einzelnes Objekt).
Unutbu
@ Rod, @ unutbu: Verstanden. Daher können lambdas Tupel nicht wie Listenverständnisse entpacken.
Dheerosaurier
3
@dheerosaur: Ja, Lambdas entpacken anders als Listenverständnisse (in Python2). Beachten Sie, dass Lambdas in Python3 das Auspacken überhaupt ablehnen: Siehe diveintopython3.org/… .
Unutbu
7

Alternativ können Sie ein Listenverständnis anstelle von map () und Lambda verwenden.

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

Ausgabe:

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

Listenverständnisse sind sehr leistungsfähig und auch schneller als eine Kombination von mapund lambda.

Prydie
quelle
8
list.index()ist nur angemessen, wenn alle Mitglieder von ranked_userseindeutig sind. Gegebene ranked_users = ['chris','chris'] user_detailsAusgaben, [{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 0}]wo es sein sollte [{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 1}].
Thisgeek
Es wäre nur sinnvoll (angesichts dieser Daten), wenn die Mitglieder einzigartig wären…
Prydie
Sicher. Ihre Antwort passt zum Beispiel. Ich dachte nur, es wäre eine gute Idee, die Einschränkung der Einzigartigkeit für jeden darzulegen, der auf diesen Beitrag stößt.
Thisgeek
Die Verwendung des Indexfunktionsaufrufs in der Liste "ranked_users" ist ein wenig überarbeitet. Python für Ausdruck iteriert über Objekte in der Datenstruktur
Cheshire Cat
6

Meiner Meinung nach ging es um die Kartenfunktion, und die bevorzugte Antwort ist teilweise richtig, da Syntaxfehler durch das Setzen von Tupelargumenten auf Lambda verursacht wurden lambda (i,x)

Idee der Aufzählung ist schön und richtige Lösung wäre:

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

und etwas Zeit, um Geschwindigkeit mit Verständnis zu vergleichen:

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))

Testergebnis: Das Listenverständnis ist in diesem Testfall etwa 1,31-mal schneller als die Karte

Cheshire Katze
quelle
2

Tatsächlich ist hier eine elegantere, ausführlichere Lösung als die Verwendung eines Aufzählungstupels in der Karte (aufgrund der Tupelindizierung). Map kann mehr iterable als Argumente verwenden, also verwenden wir es.

map(lambda user, user_id: (user_id, user), ranked_users, range(ranked_users.__len__()))
xbalaj
quelle