Извлечение уникальных предметов из списка сопоставлений - PullRequest
2 голосов
/ 09 октября 2008

Он интересная проблема, которая ищет наиболее питонское решение. Предположим, у меня есть список отображений {'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]

Полагаю, это довольно эффективно. Но есть ли "более Pythonic" способ? Или, может быть, более эффективный способ?

Ответы [ 3 ]

4 голосов
/ 09 октября 2008

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

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)), если вам нужен список, а не генератор.

2 голосов
/ 09 октября 2008

Есть пара вещей, которые вы могли бы улучшить.

  • Вы выполняете два цикла, один над исходным диктом, а затем снова над результирующим. Вместо этого вы можете создать свои результаты за один шаг.

  • Вы можете перейти на использование генератора, чтобы не создавать весь список заранее. (Используйте 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'])
1 голос
/ 09 октября 2008

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

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