2008-10-09 5 views
2

Он интересная проблема, которая ищет наиболее Pythonic решение. Предположим, у меня есть список отображений {'id': id, 'url': url}. Некоторые id s в списке дубликаты, и я хочу создать новый список, удалив все дубликаты. Я придумал следующую функцию:Извлечение уникальных предметов из списка сопоставлений

def unique_mapping(map): 
    d = {} 
    for res in map: 
     d[res['id']] = res['url'] 

    return [{'id': id, 'url': d[id]} for id in d] 

Я полагаю, что это довольно эффективно. Но есть ли «более питонический» способ? Или, может быть, более эффективным способом?

ответ

4

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

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

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

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

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

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

>>> 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'}] 
Смежные вопросы