Учитывая список словарей, как я могу удалить дубликаты одного ключа и отсортировать по другому - PullRequest
11 голосов
/ 03 февраля 2012

Я работаю с 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 s 'name'уже в списке и затем проверяет, является ли его 'score' больше, чем существующий 'score'.

Ответы [ 7 ]

15 голосов
/ 03 февраля 2012

Один из способов сделать это:

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'}]
10 голосов
/ 03 февраля 2012

Здесь нет необходимости в 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'}]
4 голосов
/ 03 февраля 2012

Просто для удовольствия, вот чисто функциональный подход:

>>> map(dict, dict(sorted(map(sorted, map(dict.items, s)))).items())
[{'score': 3, 'name': 'Bar'}, {'score': 2, 'name': 'Baz'}, {'score': 3, 'name': 'Foo'}]
3 голосов
/ 03 февраля 2012

Сортировка - это полдела.

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
2 голосов
/ 03 февраля 2012

Я думаю, что могу придумать однострочник здесь:

result = dict((x['name'],x) for x in sorted(data,key=lambda x: x['score'])).values()
2 голосов
/ 03 февраля 2012

Если вы еще не слышали о группе, используйте ее:

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}]
2 голосов
/ 03 февраля 2012

Это самый простой способ, о котором я могу подумать:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...