Obtendo uma lista de valores de uma lista de dictos

184

Eu tenho uma lista de ditados como este:

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

eu quero ['apple', 'banana', 'cars']

Qual é a melhor forma de fazer isso?

SuperString
fonte

Respostas:

324

Supondo que cada ditado tenha uma valuechave, você pode escrever (assumindo que sua lista seja nomeada l)

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

Se valueestiver faltando, você pode usar

[d['value'] for d in l if 'value' in d]
Ismail Badawi
fonte
8
Para tratar o valor ausente de uma chave, também é possível usar d.get ("key_to_lookup", "alternate_value"). Então, parecerá: [d.get ('value', 'alt') para d em l]. Se o valor não estiver presente como chave, ele simplesmente retornará 'alt'.
abhinav
Obrigado pela solução
Ajay Kumar
Essa "mágica" é conhecida como compreensão de lista docs.python.org/3/tutorial/…
William Ardila
34

Aqui está outra maneira de fazer isso usando as funções map () e lambda:

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

onde eu sou a lista. Eu vejo esse caminho "mais sexy", mas faria isso usando a compreensão da lista.

Atualização: Caso esse 'valor' possa estar faltando como uso principal:

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

Atualização: Eu também não sou muito fã de lambdas, prefiro citar coisas ... é assim que eu faria com isso em mente:

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

Eu iria ainda mais longe e criaria uma única função que explicitamente diz o que quero alcançar:

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

Com o Python 3, como mapretorna um iterador, use listpara retornar uma lista, por exemplo list(map(operator.itemgetter('value'), l)).

Anler
fonte
1
Bruto! A compreensão da lista faz muito mais sentido aqui.
Mike Graham
4
Se você for usar o primeiro map, use operator.itemgetter('value'), não a lambda.
agf
18
[x['value'] for x in list_of_dicts]
Michał Trybus
fonte
ou [d.getkey ('value') para d em dict_list]
rplnt
1
@rpInt Hum, não existe tal coisa getkey.. você quer dizer d.get('value')? Seria o mesmo que a segunda lista de @ isbadawi, não a de Michal.
agf
3
Sim, desculpe, eu quis dizer pegar. E eu quis dizer isso como algo que não gera exceção se a chave estiver faltando. Mas a solução do @ isbadawi é melhor, pois o get () fornecerá None (ou o que especificarmos como padrão) quando a chave estiver ausente.
Rplnt 01/09
5

Para um caso muito simples como esse, uma compreensão, como na resposta de Ismail Badawi é definitivamente o caminho a percorrer.

Mas quando as coisas ficam mais complicadas e você precisa começar a escrever compreensões com várias cláusulas ou aninhadas com expressões complexas, vale a pena procurar outras alternativas. Existem algumas maneiras diferentes (quase) padrão de especificar pesquisas no estilo XPath em estruturas de dict-and-list aninhadas, como JSONPath, DPath e KVC. E existem boas bibliotecas no PyPI para eles.

Aqui está um exemplo com a biblioteca nomeada dpath, mostrando como ela pode simplificar algo um pouco mais 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'}]}

Ou, 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']

Este pode não parecer tão simples à primeira vista, porque findretorna objetos correspondentes, que incluem todos os tipos de coisas além do valor correspondente, como um caminho diretamente para cada item. Porém, para expressões mais complexas, a possibilidade de especificar um caminho como, em '*.[*].value'vez de uma cláusula de compreensão, para cada um *pode fazer uma grande diferença. Além disso, o JSONPath é uma especificação independente de idioma e existem até testadores on-line que podem ser muito úteis para depuração.

abarnert
fonte
1

Eu acho que tão simples como abaixo daria o que você está procurando.

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

Você pode fazer isso com uma combinação de mapelambda também, mas a compreensão da lista parece mais elegante e pitônica.

Para uma compreensão menor da lista de entradas, é o caminho a percorrer, mas se a entrada for realmente grande, acho que os geradores são a maneira 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'

Aqui está uma comparação de todas as soluções possíveis para maior 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 você pode ver, os geradores são uma solução melhor em comparação com os outros, o mapa também é mais lento em comparação com o gerador, pelo que deixarei a OP descobrir.

Rohit
fonte
1

Siga o exemplo --

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. UMA
fonte
1

Obter valores-chave da lista de dicionários em python?

  1. Obter valores-chave da lista de dicionários em python?

Ex:

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

para d em dados:

  for key,value in d.items(): 

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

Resultado:

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

Uma maneira muito simples de fazer isso é:

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

Resultado:

['maçã', 'banana', 'carros']

Ayushi
fonte