Создать словарь из списка словарей с несколькими повторяющимися ключами и выбрать максимальное значение из этого списка - PullRequest
0 голосов
/ 29 ноября 2018

Я знаю, что есть много постов, связанных со словарными операциями, но я не смог найти решение для моего особого случая.У меня есть список словаря (повторяющиеся словарные ключи с одинаковыми или разными значениями), и я должен создать новый словарь из этого списка.Например:

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]

Вывод, который я ищу:

{'a': 2, 'b':2, 'c': 1}

Итак, как вы можете видеть, я просто хочу одну запись на ключ из списка, и значение для этого ключа будет макс.всех ценностей.Надеюсь, это не слишком запутанно.Я пришел с рабочей душой, но я просто хотел проверить, есть ли более питонический ответ на это (с меньшим количеством строк или лучшим способом). Это мое рабочее решение:

d = {}
for i in a:
    if not d.get(i.keys()[0]):
        d.update(i)
    elif d.get(i.keys()[0], 0) < i.values()[0]:
        d.update(i)
print d

Спасибо за ваше время.

Ответы [ 4 ]

0 голосов
/ 29 ноября 2018

Вы можете отсортировать список a так, чтобы одинаковые клавиши были группами, а самые большие значения были последними.Затем добавьте значения так, чтобы последним значением было значение, оставленное в dict:

>>> a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]
>>> {k:v for k,v in (x.items()[0] for x in sorted(a))}
{u'a': 2, u'c': 1, u'b': 2}

Или альтернативный синтаксис:

>>> dict(x.items()[0] for x in sorted(a))

Для синтаксиса Python 2 и 3:

>>> {k:v for k,v in (sorted(list(x.items())[0] for x in a))}
{'a': 2, 'b': 2, 'c': 1}
>>> dict(sorted(list(x.items())[0] for x in a))
{'a': 2, 'b': 2, 'c': 1}

Из комментариев: что здесь происходит?

Сначала давайте подойдем к более поучительному примеру:

>>> a = [{u'a': -1}, {u'a': -11}, {u'a': -3}, {u'b': 0}, {u'b': 100}, {u'c': 3}, {u'c': 1}]

Итак, желаемоеРезультатом здесь являются ключи (для Python 3, которые поддерживают порядок в dict или с OrderedDict): i) ключи в группах отсортированных значений и затем ii) значения, интерпретируемые как числа в возрастающих значениях.

Так что попробуйте этоfirst:

>>> sorted(list(x.items())[0] for x in a)
[('a', -11), ('a', -3), ('a', -1), ('b', 0), ('b', 100), ('c', 1), ('c', 3)]

Разбейте его на части:

sorted(list(x.items())[0] for x in a)
       ^                            ^ comprehension of
                                 ^  a list of one element dicts
         ^       ^     ^            convert to a two element tuple
  ^                                 sort the tuple first by key, then by value

Так что это работает, сортируя кортежи сначала по ключам, а затем по значениям.

Что приводит к альтернативному решению с использованием groupby:

>>> from itertools import groupby
>>> for k,v in groupby(sorted(list(x.items())[0] for x in a), key=lambda t: t[0]):
...     print(k, max(v))
... 
a ('a', -1)
b ('b', 100)
c ('c', 3)

Решение groupby будет значительно более удобным для памяти, так как оно не создает дополнительного списка.Первое решение, скорее всего, будет быстрее с меньшим списком диктов, поскольку сортировка проще (но вам нужно это проверить.)

Это не требуется в решении, которое ядал, чтобы ключи были сгруппированы (требуется для работы groupby).Это тоже работает:

 >>> sorted((list(x.items())[0] for x in a), key=lambda t: t[1])
 [('a', -11), ('a', -3), ('a', -1), ('b', 0), ('c', 1), ('c', 3), ('b', 100)]

Затем превратите его в dict с функцией построения dict.Напомним, что список кортежей занимает (key, value):

>>> dict(sorted((list(x.items())[0] for x in a), key=lambda t: t[1]))
{'a': -1, 'b': 100, 'c': 3}
0 голосов
/ 29 ноября 2018

Вы можете использовать defaultdict:

from collections import defaultdict

d = defaultdict(lambda: 0)
for val in a:
    if d[val.keys()[0]] < val.values()[0]:
        d[val.keys()[0]] = val.values()[0]

Выход

{u'a': 2, u'b': 2, u'c': 1}
0 голосов
/ 29 ноября 2018

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

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]
new_a = {}

for dict_ in a:
    key, value = list(dict_.items())[0]
    if key not in new_a or new_a[key] < value:
        new_a[key] = value

print(new_a) # -> {'c': 1, 'b': 2, 'a': 2}
0 голосов
/ 29 ноября 2018

Вы можете сделать:

a = [{u'a': 1}, {u'a': 2}, {u'a': 1}, {u'b': 2}, {u'b': 1}, {u'c': 1}, {u'c': 1}]

result = {}
for di in a:
    for key, value in di.items():
        result[key] = max(value, result.get(key, value))
print(result)

Вывод

{'a': 2, 'c': 1, 'b': 2}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...