Для многих случаев использования вы хотите получить ответ:
ys = set(y)
[item for item in x if item not in ys]
Это гибрид между ответом aaronasterling в и ответ quantumSoup в .
Версия aaronasterling выполняет len(y)
сравнение элементов для каждого элемента x
, поэтому требуется квадратичное время. В версии QuantumSoup используются наборы, поэтому для каждого элемента выполняется поиск по одному набору с постоянным временем, x
но, поскольку он преобразует оба x
и y
в наборы, он теряет порядок ваших элементов.
Преобразуя только y
в набор и повторяя x
по порядку, вы получаете лучшее из обоих миров - линейного времени и сохранения порядка. *
Однако в версии QuantumSoup все еще есть проблема: она требует, чтобы ваши элементы были хэшируемыми. Это в значительной степени встроено в природу наборов. ** Если вы пытаетесь, например, вычесть список диктов из другого списка, но список для вычитания велик, что вы делаете?
Если вы можете украсить ваши значения так, чтобы они были хэшируемыми, это решит проблему. Например, с плоским словарем, значения которого сами по себе могут быть хэшируемыми:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
Если ваши типы немного сложнее (например, вы часто имеете дело с JSON-совместимыми значениями, которые являются хэшируемыми, или списками или указаниями, значения которых имеют рекурсивный тип), вы все равно можете использовать это решение. Но некоторые типы просто не могут быть преобразованы во что угодно
Если ваши элементы не являются и не могут быть сделаны хэшируемыми, но они сопоставимы, вы можете, по крайней мере, получить логарифмическое время ( O(N*log M)
что намного лучше, чем O(N*M)
время решения списка, но не так хорошо, как O(N+M)
время заданного раствора) путем сортировки и с помощью bisect
:
ys = sorted(y)
def bisect_contains(seq, item):
index = bisect.bisect(seq, item)
return index < len(seq) and seq[index] == item
[item for item in x if bisect_contains(ys, item)]
Если ваши элементы не являются ни хэшируемыми, ни сопоставимыми, то вы застряли с квадратичным решением.
* Обратите внимание, что вы также можете сделать это, используя пару OrderedSet
объектов, для которых вы можете найти рецепты и сторонние модули. Но я думаю, что это проще.
** Причина, по которой поиск выполняется с постоянным временем, заключается в том, что все, что ему нужно сделать, - это хэшировать значение и посмотреть, есть ли запись для этого хэша. Если он не может хэшировать значение, это не сработает.