Obtener una lista de valores de una lista de dictados

184

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
fuente

Respuestas:

324

Suponiendo que cada dict tiene una valueclave, puede escribir (suponiendo que su lista tenga un nombre l)

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

Si valuepuede faltar, puede usar

[d['value'] for d in l if 'value' in d]
Ismail Badawi
fuente
8
Para tratar el valor faltante de una clave, también se puede usar d.get ("key_to_lookup", "alternate_value"). Entonces, se verá así: [d.get ('valor', 'alt') para d en l]. Si el valor no está presente como clave, simplemente devolverá 'alt'.
abhinav
Gracias por la solución
Ajay Kumar
Esta "magia" se conoce como comprensión de listas docs.python.org/3/tutorial/…
William Ardila
34

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

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

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

Actualización: en caso de que ese 'valor' pueda faltar como uso clave:

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

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

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

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

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

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

Anler
fuente
1
¡Bruto! La comprensión de la lista tiene mucho más sentido aquí.
Mike Graham
44
Si va a usar el primero map, use operator.itemgetter('value'), no a lambda.
agf
18
[x['value'] for x in list_of_dicts]
Michał Trybus
fuente
o [d.getkey ('value') para d en dict_list]
rplnt
1
@rpInt Um, no hay tal cosa como getkey... ¿quieres decir d.get('value')? Eso sería lo mismo que la comprensión de la segunda lista de @ isbadawi, no la de Michal.
agf
3
Sí, lo siento, quise decir llegar. Y lo dije como algo que no arrojará una excepción si falta la clave. Pero la solución de @ isbadawi es mejor ya que get () no proporcionará Ninguno (o lo que especifiquemos por defecto) cuando falta la clave.
rplnt
5

Para un caso muy simple como este, una comprensión, como en la respuesta de Ismail Badawi, es definitivamente el camino a seguir.

Pero cuando las cosas se vuelven más complicadas y necesita comenzar a escribir comprensiones de múltiples cláusulas o anidadas con expresiones complejas, vale la pena buscar otras alternativas. Hay algunas formas diferentes (casi) estándar para especificar búsquedas de estilo XPath en estructuras anidadas de dict-and-list, como JSONPath, DPath y KVC. Y hay buenas bibliotecas en PyPI para ellos.

Aquí hay un ejemplo con la biblioteca llamada dpath, que muestra cómo puede simplificar algo un poco más complicado:

>>> dd = {
...     'fruits': [{'value': 'apple', 'blah': 2}, {'value': 'banana', 'blah': 3}],
...     'vehicles': [{'value': 'cars', 'blah':4}]}

>>> {key: [{'value': d['value']} for d in value] for key, value in dd.items()}
{'fruits': [{'value': 'apple'}, {'value': 'banana'}],
 'vehicles': [{'value': 'cars'}]}

>>> dpath.util.search(dd, '*/*/value')
{'fruits': [{'value': 'apple'}, {'value': 'banana'}],
 'vehicles': [{'value': 'cars'}]}

O, usando jsonpath-ng:

>>> [d['value'] for key, value in dd.items() for d in value]
['apple', 'banana', 'cars']
>>> [m.value for m in jsonpath_ng.parse('*.[*].value').find(dd)]
['apple', 'banana', 'cars']

A primera vista, este puede no parecer tan simple, porque finddevuelve objetos de coincidencia, que incluyen todo tipo de cosas además del valor coincidente, como una ruta directamente a cada elemento. Pero para expresiones más complejas, poder especificar una ruta como en '*.[*].value'lugar de una cláusula de comprensión para cada una *puede hacer una gran diferencia. Además, JSONPath es una especificación independiente del idioma, e incluso hay probadores en línea que pueden ser muy útiles para la depuración.

abarnert
fuente
1

Creo que tan simple como a continuación le daría lo que está 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']

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

Para una lista de entrada más pequeña, la comprensión es un camino a seguir, pero si la entrada es realmente grande, 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 descubra.

Rohit
fuente
1

Sigue el ejemplo --

songs = [
{"title": "happy birthday", "playcount": 4},
{"title": "AC/DC", "playcount": 2},
{"title": "Billie Jean", "playcount": 6},
{"title": "Human Touch", "playcount": 3}
]

print("===========================")
print(f'Songs --> {songs} \n')
title = list(map(lambda x : x['title'], songs))
print(f'Print Title --> {title}')

playcount = list(map(lambda x : x['playcount'], songs))
print(f'Print Playcount --> {playcount}')
print (f'Print Sorted playcount --> {sorted(playcount)}')

# Aliter -
print(sorted(list(map(lambda x: x['playcount'],songs))))
Mohan UNA
fuente
1

¿Obtener valores clave de la lista de diccionarios en Python?

  1. ¿Obtener valores clave de la lista de diccionarios en Python?

Ex:

data = 
[{'obj1':[{'cpu_percentage':'15%','ram':3,'memory_percentage':'66%'}]},
{'obj2': [{'cpu_percentage':'0','ram':4,'memory_percentage':'35%'}]}]

para d en datos:

  for key,value in d.items(): 

      z ={key: {'cpu_percentage': d['cpu_percentage'],'memory_percentage': d['memory_percentage']} for d in value} 
      print(z)

Salida:

{'obj1': {'cpu_percentage': '15%', 'memory_percentage': '66%'}}
{'obj2': {'cpu_percentage': '0', 'memory_percentage': '35%'}}
Kalyani B
fuente
-2

Una forma muy simple de hacerlo es:

list1=['']
j=0
for i in com_list:
    if j==0:
        list1[0]=(i['value'])
    else:
        list1.append(i['value'])
    j+=1

Salida:

['manzana', 'plátano', 'autos']

Ayushi
fuente