Obtener una lista de valores de una lista de dictados

Resuelto SuperString asked hace 13 años • 10 respuestas

Tengo una lista de dictados como este:

[{'value': 'apple', 'blah': 2}, 
 {'value': 'banana', 'blah': 3} , 
 {'value': 'cars', 'blah': 4}]

Quiero['apple', 'banana', 'cars']

¿Cuál es la mejor manera de hacer esto?

SuperString avatar Sep 01 '11 21:09 SuperString
Aceptado

Suponiendo que cada dictado tenga una valueclave, puede escribir (suponiendo que su lista se llame l)

[d['value'] for d in l]

Si valuefalta, puedes usar

[d['value'] for d in l if 'value' in d]
Ismail Badawi avatar Sep 01 '2011 14:09 Ismail Badawi

Aquí hay otra forma de hacerlo usando las funciones map() y lambda:

>>> map(lambda d: d['value'], l)

donde l es la lista. Veo esta manera "más sexy", pero lo haría usando la lista de comprensión.

Actualización: en caso de que falte ese 'valor' como clave, utilice:

>>> map(lambda d: d.get('value', 'default value'), l)

Actualización: Tampoco soy un gran admirador de las lambdas, prefiero nombrar las cosas... así es como lo haría con eso en mente:

>>> import operator
>>> get_value = operator.itemgetter('value')
>>> map(get_value, l)

Incluso iría más allá y crearía una función única que diga explícitamente lo que quiero lograr:

>>> import operator, functools
>>> get_value = operator.itemgetter('value')
>>> get_values = functools.partial(map, get_value)
>>> get_values(l)
... [<list of values>]

Con Python 3, dado que mapdevuelve un iterador, utilícelo listpara devolver una lista, por ejemplo list(map(operator.itemgetter('value'), l)).

Anler avatar Sep 01 '2011 14:09 Anler
[x['value'] for x in list_of_dicts]
Michał Trybus avatar Sep 01 '2011 14:09 Michał Trybus

Creo que tan simple como lo siguiente te dará lo que estás buscando.

In[5]: ll = [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3} , {'value': 'cars', 'blah':4}]
In[6]: ld = [d.get('value', None) for d in ll]
In[7]: ld
Out[7]: ['apple', 'banana', 'cars']

Puedes hacer esto con una combinación de mapy lambdatambién, pero la comprensión de la lista parece más elegante y pitónica.

Para una lista de entrada más pequeña, la comprensión es un camino por recorrer, pero si la entrada es realmente grande, entonces supongo que los generadores son la forma ideal.

In[11]: gd = (d.get('value', None) for d in ll)
In[12]: gd
Out[12]: <generator object <genexpr> at 0x7f5774568b10>
In[13]: '-'.join(gd)
Out[13]: 'apple-banana-cars'

Aquí hay una comparación de todas las soluciones posibles para una mayor entrada.

 In[2]: l = [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3} , {'value': 'cars', 'blah':4}] * 9000000
In[3]: def gen_version():
  ...:     for i in l:
  ...:         yield i.get('value', None)
  ...: 
In[4]: def list_comp_verison():
  ...:     return [i.get('value', None) for i in l]
  ...: 
In[5]: def list_verison():
  ...:     ll = []
  ...:     for i in l:
  ...:         ll.append(i.get('value', None))
  ...:     return ll
In[10]: def map_lambda_version():
   ...:      m = map(lambda i:i.get('value', None), l)
   ...:      return m
   ...: 
In[11]: %timeit gen_version()
172 ns ± 0.393 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In[12]: %timeit map_lambda_version()
203 ns ± 2.31 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In[13]: %timeit list_comp_verison()
1.61 s ± 20.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In[14]: %timeit list_verison()
2.29 s ± 4.58 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Como puede ver, los generadores son una mejor solución en comparación con los demás, el mapa también es más lento en comparación con el generador, por lo que dejaré que OP lo resuelva.

Rohit avatar Jan 11 '2019 10:01 Rohit