Получение списка значений из списка диктов


185

У меня есть список таких слов:

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

я хочу ['apple', 'banana', 'cars']

Какой лучший способ сделать это?

Ответы:


326

Предполагая, что у каждого dict есть valueключ, вы можете написать (если ваш список назван l)

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

Если valueможет отсутствовать, вы можете использовать

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

8
Чтобы обработать пропущенное значение для ключа, можно также использовать d.get ("key_to_lookup", "alternate_value"). Тогда это будет выглядеть так: [d.get ('value', 'alt') для d в l]. Если значение отсутствует в качестве ключа, оно просто вернет 'alt'.
Абхинав

Спасибо за решение
Аджай Кумар

Эта «магия» известна как понимание списка docs.python.org/3/tutorial/…
Уильям Ардила

Спасатель жизни! Я пытался / искал это для объектов sqlalchemy с тех пор. Теперь это работает как [d.value for d in l]спасибо :)
Крупеш Анадкат

34

Вот еще один способ сделать это с помощью функций map () и lambda:

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

где л список. Я вижу этот путь "самым сексуальным", но я бы сделал это, используя понимание списка.

Обновление: в случае, если это значение может отсутствовать в качестве ключа:

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

Обновление: я также не большой поклонник лямбд, я предпочитаю называть вещи ... вот как я бы сделал это с учетом этого:

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

Я бы даже пошел дальше и создал бы единственную функцию, которая явно говорит о том, чего я хочу достичь:

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

В Python 3, поскольку mapвозвращает итератор, используйте listдля возврата списка, например list(map(operator.itemgetter('value'), l)).


1
Валовой! Понимание списка имеет гораздо больше смысла здесь.
Майк Грэм

4
Если вы собираетесь использовать первый map, используйте operator.itemgetter('value'), а не lambda.
AGF

18
[x['value'] for x in list_of_dicts]

или [d.getkey ('value') для d в dict_list]
rplnt

1
@rpInt Хм, нет такой вещи как getkey.. ты имеешь в виду d.get('value')? Это было бы то же самое, что и понимание второго списка @ isbadawi, а не Михала.
AGF

3
Да, извини, я имел в виду получить. И я имел в виду это как то, что не будет генерировать исключение, если ключ отсутствует Но решение @ isbadawi лучше, так как get () предоставит None (или то, что мы указываем по умолчанию), когда ключ отсутствует.
rplnt

5

Для очень простого случая, подобного этому, понимание, как в ответе Исмаила Бадави определенно является подходящим вариантом.

Но когда все усложняется, и вам нужно начать писать многоузловые или вложенные понимания со сложными выражениями в них, стоит поискать другие альтернативы. Существует несколько различных (квази) стандартных способов задания поиска в стиле XPath для вложенных структур dict-and-list, таких как JSONPath, DPath и KVC. И для них есть хорошие библиотеки на PyPI.

Вот пример с библиотекой dpath, которая показывает, как она может упростить что-то немного более сложное:

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

Или, используя 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']

На первый взгляд это может показаться не таким простым, потому что findвозвращает совпадающие объекты, которые включают в себя все виды, кроме только совпадающего значения, например, путь непосредственно к каждому элементу. Но для более сложных выражений возможность указать путь, например, '*.[*].value'вместо предложения для каждого из них, *может иметь большое значение. Кроме того, JSONPath является независимой от языка спецификацией, и есть даже онлайн-тестеры, которые могут быть очень полезны для отладки.


1

Я думаю, что простое, как показано ниже, даст вам то, что вы ищете.

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

Вы можете сделать это с помощью комбинации mapиlambda но понимание списка выглядит более элегантно и питонно.

Для меньшего входного списка понимание - путь, но если вход действительно большой, тогда я предполагаю, что генераторы - идеальный способ.

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'

Вот сравнение всех возможных решений для большего вклада

 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)

Как вы можете видеть, генераторы - лучшее решение по сравнению с другими, карта также медленнее по сравнению с генератором по причине, которую я оставлю до OP, чтобы выяснить.


1

Следуй примеру --

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

1

Получить значения ключей из списка словарей в Python?

  1. Получить значения ключей из списка словарей в Python?

Пример:

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

для д в данных:

  for key,value in d.items(): 

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

Вывод:

{'obj1': {'cpu_percentage': '15%', 'memory_percentage': '66%'}}
{'obj2': {'cpu_percentage': '0', 'memory_percentage': '35%'}}

-2

Очень простой способ сделать это:

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

Вывод:

['яблоко', 'банан', 'автомобили']

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.