Это интересная проблема, которая ищет наиболее питоническое решение. Предположим, у меня есть список сопоставлений {'id': id, 'url': url}. Некоторые id в списке дублируются, и я хочу создать новый список, удалив все дубликаты. Я придумал такую функцию:
def unique_mapping(map):
d = {}
for res in map:
d[res['id']] = res['url']
return [{'id': id, 'url': d[id]} for id in d]
Полагаю, это достаточно эффективно. Но есть ли «более питонический» способ? Или, может быть, более эффективный способ?






Ваш пример можно немного переписать, чтобы построить первый словарь с использованием выражения генератора и устранить необходимость построения других отображений. Просто используйте старые:
def unique_mapping(mappings):
return dict((m['id'], m) for m in mappings).values()
Хотя это получилось однострочно, я все же думаю, что он вполне читаем.
При использовании исходного и моего решений следует помнить о двух вещах:
Если вы не возражаете, я предлагаю решение, указанное выше. В противном случае эта функция сохраняет порядок и обрабатывает первоочередные идентификаторы:
def unique_mapping(mappings):
addedIds = set()
for m in mappings:
mId = m['id']
if mId not in addedIds:
addedIds.add(mId)
yield m
Вам может потребоваться вызвать его с помощью list(unique_mappings(mappings)), если вам нужен список, а не генератор.
Есть несколько вещей, которые вы могли бы улучшить.
Вы выполняете два цикла, один над исходным dict, а затем снова над результатом dict. Вместо этого вы можете добиться результатов за один шаг.
Вы можете использовать генератор, чтобы не создавать весь список заранее. (Используйте list (unique_mapping (items)), чтобы преобразовать в полный список, если он вам нужен)
Нет необходимости сохранять значение при простой проверке дубликатов, вместо этого вы можете использовать набор.
Вы воссоздаете словарь для каждого элемента, а не возвращаете оригинал. Это может действительно быть необходимо (например, вы изменяете их и не хотите касаться оригинала), но в противном случае более эффективно использовать уже созданные словари.
Вот реализация:
def unique_mapping(items):
s = set()
for res in items:
if res['id'] not in s:
yield res
s.add(res['id'])
Думаю, это можно сделать еще проще. Словари не терпят дублирования ключей. Превратите свой список сопоставлений в словарь сопоставлений. Это удалит дубликаты.
>>> someListOfDicts= [
{'url': 'http://a', 'id': 'a'},
{'url': 'http://b', 'id': 'b'},
{'url': 'http://c', 'id': 'a'}]
>>> dict( [(x['id'],x) for x in someListOfDicts ] ).values()
[{'url': 'http://c', 'id': 'a'}, {'url': 'http://b', 'id': 'b'}]