Учитывая список словарей, как я могу устранить дубликаты одного ключа и сортировать по другому
Я работаю с объектами list
из dict
, которые выглядят следующим образом (порядок объектов отличается):
[
{'name': 'Foo', 'score': 1},
{'name': 'Bar', 'score': 2},
{'name': 'Foo', 'score': 3},
{'name': 'Bar', 'score': 3},
{'name': 'Foo', 'score': 2},
{'name': 'Baz', 'score': 2},
{'name': 'Baz', 'score': 1},
{'name': 'Bar', 'score': 1}
]
Что я хочу сделать, это удалить повторяющиеся имена, сохраняя только одно имя, имеющее наивысшее значение 'score'
. Результаты из приведенного выше списка будут следующими:
[
{'name': 'Baz', 'score': 2},
{'name': 'Foo', 'score': 3},
{'name': 'Bar', 'score': 3}
]
Я не уверен, какой шаблон использовать здесь (кроме, казалось бы, идиотского цикла, который продолжает проверять, находится ли текущий dict
'name'
в списке, а затем проверяет, находится ли его 'score'
выше существующего один 'score'
.
Ответы
Ответ 1
Один из способов сделать это:
data = collections.defaultdict(list)
for i in my_list:
data[i['name']].append(i['score'])
output = [{'name': i, 'score': max(j)} for i,j in data.items()]
поэтому вывод будет:
[{'score': 2, 'name': 'Baz'},
{'score': 3, 'name': 'Foo'},
{'score': 3, 'name': 'Bar'}]
Ответ 2
Здесь нет необходимости в defaultdicts или наборах. Вы можете просто использовать простые просты и списки.
Подведите итоговый результат в словаре и преобразуйте результат обратно в список:
>>> s = [
{'name': 'Foo', 'score': 1},
{'name': 'Bar', 'score': 2},
{'name': 'Foo', 'score': 3},
{'name': 'Bar', 'score': 3},
{'name': 'Foo', 'score': 2},
{'name': 'Baz', 'score': 2},
{'name': 'Baz', 'score': 1},
{'name': 'Bar', 'score': 1}
]
>>> d = {}
>>> for entry in s:
name, score = entry['name'], entry['score']
d[name] = max(d.get(name, 0), score)
>>> [{'name': name, 'score': score} for name, score in d.items()]
[{'score': 2, 'name': 'Baz'}, {'score': 3, 'name': 'Foo'}, {'score': 3, 'name': 'Bar'}]
Ответ 3
Просто для удовольствия, здесь есть чисто функциональный подход:
>>> map(dict, dict(sorted(map(sorted, map(dict.items, s)))).items())
[{'score': 3, 'name': 'Bar'}, {'score': 2, 'name': 'Baz'}, {'score': 3, 'name': 'Foo'}]
Ответ 4
Сортировка - это половина битвы.
import itertools
import operator
scores = [
{'name': 'Foo', 'score': 1},
{'name': 'Bar', 'score': 2},
{'name': 'Foo', 'score': 3},
{'name': 'Bar', 'score': 3},
{'name': 'Foo', 'score': 2},
{'name': 'Baz', 'score': 2},
{'name': 'Baz', 'score': 1},
{'name': 'Bar', 'score': 1}
]
result = []
sl = sorted(scores, key=operator.itemgetter('name', 'score'),
reverse=True)
name = object()
for el in sl:
if el['name'] == name:
continue
name = el['name']
result.append(el)
print result
Ответ 5
Это самый простой способ, о котором я могу думать:
names = set(d['name'] for d in my_dicts)
new_dicts = []
for name in names:
d = dict(name=name)
d['score'] = max(d['score'] for d in my_dicts if d['name']==name)
new_dicts.append(d)
#new_dicts
[{'score': 2, 'name': 'Baz'},
{'score': 3, 'name': 'Foo'},
{'score': 3, 'name': 'Bar'}]
Лично я предпочитаю не импортировать модули, когда проблема слишком мала.
Ответ 6
Если вы не слышали о группе, это приятно использовать:
from itertools import groupby
data=[
{'name': 'Foo', 'score': 1},
{'name': 'Bar', 'score': 2},
{'name': 'Foo', 'score': 3},
{'name': 'Bar', 'score': 3},
{'name': 'Foo', 'score': 2},
{'name': 'Baz', 'score': 2},
{'name': 'Baz', 'score': 1},
{'name': 'Bar', 'score': 1}
]
keyfunc=lambda d:d['name']
data.sort(key=keyfunc)
ans=[]
for k, g in groupby(data, keyfunc):
ans.append({k:max((d['score'] for d in g))})
print ans
>>>
[{'Bar': 3}, {'Baz': 2}, {'Foo': 3}]
Ответ 7
Думаю, я могу придумать однострочный:
result = dict((x['name'],x) for x in sorted(data,key=lambda x: x['score'])).values()