Как удалить все дубликаты из итерируемых по атрибутам? - PullRequest
0 голосов
/ 15 января 2020

С учетом итерируемого, например,

results = [ref_a, # references big object A
           ref_b, # references big object B
           ref_c, # references big object A
           ref_d, # references big object D
]

Ссылки - это каждый уникальный объект, но некоторые ссылаются на один и тот же (больший) объект.

Мне нужен только набор (или список) ссылок для уникальных объектов.

Мой желаемый результат, например:

custom_set = (ref_a,
              ref_b,
              ref_d,
)

Замечания

Встроенный Python set неприменим, поскольку все объекты ввода различны. Это означает, что set вернет все элементы.

Я не могу изменить определение класса для ссылок, поэтому я не могу реализовать пользовательскую функцию cmp / ha sh или аналогичную.

Это делает не имеет значения, содержит ли конечный результат ref_a или ref_c.

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

Я не могу сохранить только result.reference, так как после фильтрации мне нужно получить доступ к другим атрибутам result. Если бы я только сохранил result.reference, мне пришлось бы создать экземпляр дорогостоящего объекта.

Извините за использование result в качестве входного параметра, но я не хочу впоследствии его менять, так как ответы не будут подходит к вопросу больше. Я запомню это для будущего вопроса.

Возможно, reference также не был лучшим именованием - это больше похоже на легкий прокси-объект.

Ответы [ 3 ]

2 голосов
/ 15 января 2020

Ваш код в порядке, хотя вы можете решить эту проблему, используя itertools.groupby.

from itertools import groupby
from operator import attrgetter

f = attrgetter('reference')
custom_set = set(next(x) for _, x in groupby(sorted(results, key=f), f))

Оба sorted и groupby стабильны, поэтому next(x) гарантированно будет первым элементом в results с определенным значением атрибута reference.

Недостатком этого подхода является то, что sorted() занимает время O (n lg n) по сравнению с вашим O (n) обходом списка .

Вы также можете написать свой код как (в основном) однострочный, хотя я бы не рекомендовал его:

known = {}
custom_set = set(known.add(r.reference) and r for r in result if r.reference not in known)

known.add(r.reference) всегда будет возвращать None, поэтому значение выражения and всегда будет r, но само выражение будет оцениваться, только если r.reference еще не введено в known. Выражение and - это просто способ побочного эффекта обновления known в выражении генератора.

1 голос
/ 15 января 2020

Я придумал это решение, но должно быть лучше / больше pythoni c.

known = set()
custom_set = set()
for result in results:
    if result.reference not in known:
       known.add(result.reference)
       custom_set.add(result)
0 голосов
/ 15 января 2020

Попробуйте это

a=[]

for i in results:

    if i not in a:

        a.append(i)

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