Удалить дубликаты в списке объектов с помощью Python - PullRequest
15 голосов
/ 13 ноября 2010

У меня есть список объектов, и у меня есть таблица БД, полная записей. Мой список объектов имеет атрибут заголовка, и я хочу удалить любые объекты с дублирующимися заголовками из списка (оставив оригинал).

Затем я хочу проверить, есть ли в моем списке объектов дубликаты каких-либо записей в базе данных, и если это так, удалить эти элементы из списка, прежде чем добавлять их в базу данных.

Я видел решения для удаления дубликатов из списка: myList = list(set(myList)), но я не уверен, как это сделать со списком объектов?

Мне тоже нужно поддерживать порядок моего списка объектов. Я также подумал, может быть, я смогу использовать difflib для проверки различий в названиях.

Ответы [ 6 ]

36 голосов
/ 13 ноября 2010

set(list_of_objects) удалит дубликаты, только если вы знаете, что такое дубликат, то есть вам нужно будет определить уникальность объекта.

Для этого вам нужно сделать объект хэшируемым. Вам необходимо определить метод __hash__ и __eq__, вот как:

http://docs.python.org/glossary.html#term-hashable

Хотя вам, вероятно, нужно будет определить только метод __eq__.

РЕДАКТИРОВАТЬ : Как реализовать метод __eq__:

Вам нужно знать, как я уже говорил, определение уникальности вашего объекта. Предположим, что у нас есть книга с атрибутами author_name и title, что их комбинация уникальна (поэтому у нас может быть много книг, написанных Стивеном Кингом, и много книг с именем The Shining, но только одна книга под названием The Shining от Стивена Кинга), затем реализация выглядит следующим образом:

def __eq__(self, other):
    return self.author_name==other.author_name\
           and self.title==other.title

Точно так же иногда я реализую метод __hash__:

def __hash__(self):
    return hash(('title', self.title,
                 'author_name', self.author_name))

Вы можете проверить, что если вы создаете список из 2 книг с одинаковым автором и названием, объекты книги будут одинаковыми (с оператором is) и равными (с оператором ==) , Кроме того, при использовании set() будет удалена одна книга.

EDIT : Это один мой старый ответ, но я только сейчас замечаю, что в последнем абзаце есть ошибка, которая исправлена ​​зачеркиванием: объекты с одинаковым hash() не дадут True по сравнению с is. Однако хеш-объектность используется, если вы собираетесь использовать их как элементы набора или как ключи в словаре.

10 голосов
/ 13 ноября 2010

Поскольку они не могут быть хэшируемыми, вы не можете использовать набор напрямую. Хотя названия должны быть.

Вот первая часть.

seen_titles = set()
new_list = []
for obj in myList:
    if obj.title not in seen_titles:
        new_list.append(obj)
        seen_titles.add(obj.title)

Вам нужно будет описать, какую базу данных / ORM и т. Д. Вы используете для второй части.

1 голос
/ 13 ноября 2010

Это кажется довольно минимальным:

new_dict = dict()
for obj in myList:
    if obj.title not in new_dict:
        new_dict[obj.title] = obj
0 голосов
/ 26 ноября 2018

Для этого нужны и __hash__, и __eq__.

__hash__ требуется для добавления объекта в набор, поскольку наборы python реализованы в виде хеш-таблиц .По умолчанию неизменяемые объекты, такие как числа, строки и кортежи, являются хэшируемыми.

Однако коллизии хэшей (два разных объекта, хэширующие одно и то же значение) неизбежны из-за принципа «голубиных отверстий».Таким образом, два объекта нельзя различить, используя только их хэш, и пользователь должен указать свою собственную функцию __eq__.Таким образом, фактическая хеш-функция, которую предоставляет пользователь, не является критически важной, хотя лучше всего попытаться избежать коллизий хеша для производительности (см. Какой правильный и хороший способ реализовать __hash __ ()? ).

0 голосов
/ 20 ноября 2016

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

seen = {}
new_list = [seen.setdefault(x, x) for x in my_list if x not in seen]

Если вам не нужен порядок, используйте его:

new_list = list(set(my_list))
0 голосов
/ 17 марта 2011

Его довольно легко найти: -

a = [5,6,7,32,32,32,32,32,32,32,32]

a = список (набор (а))

печать (а)

[5,6,7,32]

вот и все!:)

...