Obtener el índice del elemento mientras se procesa una lista usando el mapa en python

4 minutos de lectura

Al procesar una lista usando map(), quiero acceder al índice del elemento mientras estoy dentro de lambda. ¿Cómo puedo hacer eso?

Por ejemplo

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

¿Cómo puedo obtener el rango de cada usuario en el ejemplo anterior?

avatar de usuario
unutbu

Usar enumerar:

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}]

PD. mi primera respuesta fue

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

Recomiendo enfáticamente usar una comprensión de lista o una expresión generadora sobre map y lambda cuando sea posible. Las listas de comprensión son más legibles y tienden a ser más rápidas de iniciar.

  • ¿Los parámetros de lambda no deberían estar sin paréntesis?

    – dinosaurio

    25 de marzo de 2011 a las 13:16


  • @dheerosaur No en este caso, ya que la operación next() en enumerate devuelve una tupla. Esta lambda es equivalente a def foo((i,x))

    – Varilla

    25 de marzo de 2011 a las 13:20

  • @dheerosaur: En realidad, los paréntesis son obligatorios. enumerate genera tuplas (un solo objeto).

    – unutbu

    25 de marzo de 2011 a las 13:21

  • @Rod, @unutbu: Lo tengo. Asi que, lambdas no puede desempaquetar tuplas como lo hacen las listas por comprensión.

    – dinosaurio

    25 de marzo de 2011 a las 13:32

  • @dheerosaur: Sí, las lambdas se desempaquetan de manera diferente a las listas de comprensión (en Python2). Tenga en cuenta que en Python3, las lambdas se niegan a desempaquetar: consulte diveintopython3.org/….

    – unutbu

    25 de marzo de 2011 a las 14:10


avatar de usuario
Prydie

Alternativamente, podría usar un lista de comprensión en lugar de map() y lambda.

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

Producción:

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

Las listas de comprensión son muy poderosas y también son más rápidas que una combinación de map y lambda.

  • list.index() sólo es apropiado si todos los miembros de ranked_users son únicos. Dado ranked_users = ['chris','chris'] user_details salidas [{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 0}] donde debería estar [{'name': 'chris', 'rank': 0}, {'name': 'chris', 'rank': 1}].

    – este geek

    25 de noviembre de 2012 a las 15:51

  • Sin embargo, solo tendría sentido (dados estos datos) que los miembros fueran únicos…

    – Pridie

    29 de noviembre de 2012 a las 11:39

  • Por supuesto. Tu respuesta se ajusta al ejemplo. Simplemente pensé que sería una buena idea indicar la advertencia de singularidad para cualquier persona que se encuentre con esta publicación.

    – este geek

    29 de noviembre de 2012 a las 18:27

  • el uso de la llamada de función de índice en la lista de usuarios clasificados está un poco sobrediseñado. Python para la expresión itera sobre objetos en la estructura de datos

    – gato de Cheshire

    16 de agosto de 2019 a las 17:10

avatar de usuario
gato de Cheshire

En mi opinión, la pregunta era sobre la función del mapa y la respuesta preferida es parcialmente correcta debido a un error de sintaxis causado al poner un argumento de tupla a lambda lambda (i,x)

la idea de enumerar es agradable y la solución adecuada sería:

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

y algunos tiempos para comparar la velocidad con la comprensión:

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

resultado de la prueba: la comprensión de la lista es aproximadamente 1,31 veces más rápida que la del mapa en este caso de prueba

avatar de usuario
xbalaj

En realidad, aquí hay una solución más elegante y detallada que usar una tupla enumerada en el mapa (debido a la indexación de tupla). El mapa puede tomar más iterables como argumentos, así que usémoslo.

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

¿Ha sido útil esta solución?