В значительной степени мне нужно написать программу, чтобы проверить, есть ли в списке какие-либо дубликаты, и если она удаляет их и возвращает новый список с элементами, которые не были дублированы/удалены. Это то, что у меня есть, но, честно говоря, я не знаю, что делать.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
Общий подход к получению уникальной коллекции элементов - использование set
. Наборы представляют собой неупорядоченные коллекции отдельных объектов. Чтобы создать набор из любого итерабельного, вы можете просто передать его во встроенную функцию set()
. Если позже вам понадобится реальный список, вы также можете передать набор в функцию list()
.
Следующий пример должен охватывать все, что вы пытаетесь сделать:
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]
Как видно из примера, исходный порядок не поддерживается. Как упоминалось выше, сами по себе являются неупорядоченными коллекциями, поэтому порядок утерян. При преобразовании набора в список создается произвольный порядок.
Если заказ важен для вас, вам придется использовать другой механизм. Очень распространенное решение для этого - полагаться на OrderedDict
чтобы сохранить порядок ключей во время вставки:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Обратите внимание, что у этого есть накладные расходы на создание словаря сначала, а затем создание списка из него. Поэтому, если вам действительно не нужно сохранять заказ, вам лучше использовать набор. Проверьте этот вопрос для получения более подробной информации и альтернативных способов сохранения порядка при удалении дубликатов.
Наконец, обратите внимание, что как set
так и решение OrderedDict
требуют, чтобы ваши объекты были хешируемыми. Обычно это означает, что они должны быть неизменными. Если вам приходится иметь дело с элементами, которые не хешируются (например, объекты списка), вам придется использовать медленный подход, в котором вам в основном придется сравнивать каждый элемент с каждым другим элементом во вложенном цикле.
В Python 2.7 новый способ удаления дубликатов из итерации при сохранении в исходном порядке:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
В Python 3.5 у OrderedDict есть реализация C. Мои тайминги показывают, что это теперь и самый быстрый и самый короткий из различных подходов для Python 3.5.
В Python 3.6 обычный dict стал как упорядоченным, так и компактным. (Эта функция выполняется для CPython и PyPy, но может отсутствовать в других реализациях). Это дает нам новый быстрый способ дедуплирования при сохранении порядка:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
В Python 3.7 регулярный dict гарантирован как для всех, так и для всех реализаций. Итак, самое короткое и быстрое решение:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Это однострочный: list(set(source_list))
выполнит трюк.
A set
- это то, что не может иметь дубликатов.
Обновление: подход, сохраняющий порядок, состоит из двух строк:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
Здесь мы используем тот факт, что OrderedDict
запоминает порядок вставки ключей и не изменяет его при обновлении значения в определенном ключе. Мы вставляем True
в качестве значений, но мы можем вставлять что угодно, значения просто не используются. (set
работает так же, как и dict
с игнорируемыми значениями.)
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
if i not in s:
s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]
Если вы не заботитесь о заказе, просто выполните следующее:
def remove_duplicates(l):
return list(set(l))
A set
гарантированно не имеет дубликатов.
Чтобы создать новый список, сохраняющий порядок первых элементов дубликатов в L
newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]
например if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]
, тогда newlist
будет [1,2,3,4,5]
Это проверяет, что каждый новый элемент не появился ранее в списке перед его добавлением. Также им не нужны импорт.
set
и OrderedDict
могут иметь меньшую сложность амортизированного времени.
Коллега отправил принятый ответ в качестве части его кода ко мне для кодового просмотра сегодня. Хотя я, конечно, восхищаюсь элегантностью ответного вопроса, я не доволен выступлением. Я пробовал это решение (я использую set для уменьшения времени поиска)
def ordered_set(in_list):
out_list = []
added = set()
for val in in_list:
if not val in added:
out_list.append(val)
added.add(val)
return out_list
Чтобы сравнить эффективность, я использовал случайную выборку из 100 целых чисел - 62 были уникальными
from random import randint
x = [randint(0,100) for _ in xrange(100)]
In [131]: len(set(x))
Out[131]: 62
Ниже приведены результаты измерений
In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop
In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop
Хорошо, что произойдет, если set будет удален из решения?
def ordered_set(inlist):
out_list = []
for val in inlist:
if not val in out_list:
out_list.append(val)
return out_list
Результат не так плох, как с OrderedDict, но еще более чем в 3 раза от исходного решения
In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
Другой способ:
>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
keys()
возвращает объект представления словаря, а не список.
Простой и легкий:
myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]
Вывод:
>>> cleanlist
[1, 2, 3, 5, 6, 7, 8]
in
операции O (n) и ваш cleanlist
будет иметь не более n
чисел => в худшем случае ~ O (n ^ 2)
Существуют также решения с использованием Pandas и Numpy. Они возвращают массив numpy, поэтому вам нужно использовать функцию .tolist()
если вам нужен список.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
Использование функции Pandas unique()
:
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Использование функции numpy unique()
.
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
Обратите внимание, что numpy.unique() также сортирует значения. Таким образом, список t2
будет отсортирован. Если вы хотите сохранить сохраненный порядок, как в этом ответе:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
Решение не настолько элегантно по сравнению с другими, однако по сравнению с pandas.unique(), numpy.unique() позволяет также проверить, уникальны ли вложенные массивы вдоль одной выбранной оси.
У меня был указатель в моем списке, поэтому я не мог использовать вышеупомянутый подход. Я получил ошибку:
TypeError: unhashable type:
Итак, если вам нужен порядок и/или некоторые элементы расчесываются. Тогда вы можете найти это полезным:
def make_unique(original_list):
unique_list = []
[unique_list.append(obj) for obj in original_list if obj not in unique_list]
return unique_list
Некоторые могут рассмотреть понимание списка с побочным эффектом, чтобы не быть хорошим решением. Вот альтернатива:
def make_unique(original_list):
unique_list = []
map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
return unique_list
map
с побочным эффектом еще более обманчива, чем listcomp с побочным эффектом. Кроме того, lambda x: unique_list.append(x)
- просто более медленный и более медленный способ передать unique_list.append
.
Все подходы, OrderedDicts
порядок, которые я видел здесь, пока используют либо наивное сравнение (с наилучшей сложностью O (n ^ 2)), либо тяжелые команды OrderedDicts
/set
+ list
, которые ограничены входами хешируемого. Вот хеш-независимое решение O (nlogn):
Обновление добавило key
аргумент, документацию и совместимость с Python 3.
# from functools import reduce <-- add this import on Python 3
def uniq(iterable, key=lambda x: x):
"""
Remove duplicates from an iterable. Preserves order.
:type iterable: Iterable[Ord => A]
:param iterable: an iterable of objects of any orderable type
:type key: Callable[A] -> (Ord => B)
:param key: optional argument; by default an item (A) is discarded
if another item (B), such that A == B, has already been encountered and taken.
If you provide a key, this condition changes to key(A) == key(B); the callable
must return orderable objects.
"""
# Enumerate the list to restore order lately; reduce the sorted list; restore order
def append_unique(acc, item):
return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc
srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))]
tuple()
списков и их хэширования. | | | | - Вообще говоря, процесс хеширования занимает время, пропорциональное размеру целых данных, в то время как это решение занимает время O (nlog (n)), зависящее только от длины списка.
Вы также можете сделать это:
>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]
Причина, по которой выше, заключается в том, что метод index
возвращает только первый индекс элемента. Дублирующие элементы имеют более высокие индексы. См. здесь:
list.index(x [, start [, end]])
Возвращать индекс на основе нуля в списке первый элемент, значение которого равно x. Повышает значение ValueError, если нет такой пункт.
list.index
- это операция с линейным временем, делающая ваше решение квадратичным.
Попробуйте использовать наборы:
import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])
print t | t1
print t - t1
Без использования set
data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
if dat not in uni_data:
uni_data.append(dat)
print(uni_data)
Лучший способ удаления дубликатов из списка - использовать функцию set(), доступную в python, снова конвертируя этот в список
In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
Есть много других ответов, предлагающих разные способы сделать это, но они все пакетные операции, а некоторые из них выбрасывают исходный порядок. Это может быть в порядке, в зависимости от того, что вам нужно, но если вы хотите перебирать значения в порядке первого экземпляра каждого значения, и вы хотите удалить дубликаты "на лету" против всех одновременно, вы можете использовать этот генератор:
def uniqify(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
Это возвращает генератор/итератор, поэтому вы можете использовать его в любом месте, где вы можете использовать итератор.
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
print(unique_item, end=' ')
print()
Вывод:
1 2 3 4 5 6 7 8
Если вам нужен list
, вы можете сделать это:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
print(unique_list)
Вывод:
[1, 2, 3, 4, 5, 6, 7, 8]
seen = set(iterable); for item in seen: yield item
почти наверняка быстрее. (Я не пробовал этот конкретный случай, но это было бы мое предположение.)
ниже код прост для удаления дубликата в списке
def remove_duplicates(x):
a = []
for i in x:
if i not in a:
a.append(i)
return a
print remove_duplicates([1,2,2,3,3,4])
он возвращает [1,2,3,4]
list(set(..))
(более 1 миллиона проходов) побьет это решение примерно на 10 полных секунд - тогда как этот подход занимает около 12 секунд, list(set(..))
занимает всего около 2 секунд!
Уменьшить вариант с сохранением порядка:
Предположим, что у нас есть список:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
Уменьшить вариант (неэффективно):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
5 быстрее, но сложнее
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]
Пояснение:
default = (list(), set())
# user list to keep order
# use set to make lookup faster
def reducer(result, item):
if item not in result[1]:
result[0].append(item)
result[1].add(item)
return result
reduce(reducer, l, default)[0]
Этот человек заботится о заказе без особых хлопот (OrderdDict и другие). Вероятно, это не самый питоновский путь или кратчайший путь, но делает трюк:
def remove_duplicates(list):
''' Removes duplicate items from a list '''
singles_list = []
for element in list:
if element not in singles_list:
singles_list.append(element)
return singles_list
list
); 2. Ваш метод очень плохо масштабируется: он квадратичен по количеству элементов в list
.
Еще один лучший подход может быть,
import pandas as pd
myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)
#> [1, 2, 3, 5, 6, 7, 8]
и порядок остается сохраненным.
Очень простой способ в Python 3:
>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]
sorted(list(...))
является избыточным ( sorted
уже неявно преобразует свой аргумент в новый list
, сортирует его, затем возвращает новый list
, поэтому использование обоих способов означает создание ненужного временного list
). Используйте только list
если результат не нужно сортировать, используйте только sorted
если результат должен быть отсортирован.
Использование set:
a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a
Использование уникальный:
import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a
Здесь самое быстрое питоновское решение, дружественное к другим, перечисленным в ответах.
Использование деталей реализации оценки короткого замыкания позволяет использовать понимание списка, которое достаточно быстро. visited.add(item)
всегда возвращает None
в результате, который оценивается как False
, поэтому правая часть or
всегда будет результатом такого выражения.
Время это самостоятельно
def deduplicate(sequence):
visited = set()
adder = visited.add # get rid of qualification overhead
out = [adder(item) or item for item in sequence if item not in visited]
return out
Вы можете использовать set
для удаления дубликатов:
mylist = list(set(mylist))
Но обратите внимание, что результаты будут неупорядоченными. Если это проблема:
mylist.sort()
Я думаю, что преобразование в набор - это самый простой способ удалить дубликат:
list1 = [1,2,1]
list1 = list(set(list1))
print list1
Отметьте это, если вы хотите удалить дубликаты (вместо редактирования нового списка) вместо использования встроенного набора, dict.keys, uniqify, counter
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> for i in t:
... if i in t[t.index(i)+1:]:
... t.remove(i)
...
>>> t
[3, 1, 2, 5, 6, 7, 8]
enumerate()
чтобы получить индекс быстрее: for i, value in enumerate(t): if value in t[i + 1:]: t.remove(value)
[1,1,1]
Вот пример, возвращающий список без сохранения порядка повторения. Не требуется никакого внешнего импорта.
def GetListWithoutRepetitions(loInput):
# return list, consisting of elements of list/tuple loInput, without repetitions.
# Example: GetListWithoutRepetitions([None,None,1,1,2,2,3,3,3])
# Returns: [None, 1, 2, 3]
if loInput==[]:
return []
loOutput = []
if loInput[0] is None:
oGroupElement=1
else: # loInput[0]<>None
oGroupElement=None
for oElement in loInput:
if oElement<>oGroupElement:
loOutput.append(oElement)
oGroupElement = oElement
return loOutput
В настоящее время вы можете использовать класс Counter:
>>> import collections
>>> c = collections.Counter([1, 2, 3, 4, 5, 6, 1, 1, 1, 1])
>>> c.keys()
dict_keys([1, 2, 3, 4, 5, 6])
Вы можете использовать следующую функцию:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
Пример:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
Использование:
rem_dupes(my_list)
['this', 'is', 'a', 'list', 'with', 'dupicates', 'in', 'the']
Другим решением может быть следующее. Создайте словарь из списка с элементом как ключом и индексом как значение, а затем распечатайте словарные ключи.
>>> lst = [1, 3, 4, 2, 1, 21, 1, 32, 21, 1, 6, 5, 7, 8, 2]
>>>
>>> dict_enum = {item:index for index, item in enumerate(lst)}
>>> print dict_enum.keys()
[32, 1, 2, 3, 4, 5, 6, 7, 8, 21]
list(set(lst))
достиг бы того же логического результата.
Здесь много ответов, в которых используется set(..)
(который быстро задан для хэширования элементов) или список (который имеет недостаток, который приводит к алгоритму O (n 2).
Функция, которую я предлагаю, является гибридной: мы используем set(..)
для элементов, которые являются хешируемыми, и list(..)
для тех, которые не являются. Кроме того, он реализуется как генератор, так что мы можем, например, ограничить количество элементов или сделать некоторую дополнительную фильтрацию.
Наконец, мы также можем использовать key
аргумент, чтобы указать, каким образом элементы должны быть уникальными. Например, мы можем использовать это, если мы хотим отфильтровать список строк таким образом, чтобы каждая строка на выходе имела разную длину.
def uniq(iterable, key=lambda x: x):
seens = set()
seenl = []
for item in iterable:
k = key(item)
try:
seen = k in seens
except TypeError:
seen = k in seenl
if not seen:
yield item
try:
seens.add(k)
except TypeError:
seenl.append(k)
Теперь мы можем использовать это, например:
>>> list(uniq(["apple", "pear", "banana", "lemon"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", "lemon", "banana"], len))
['apple', 'pear', 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"], len))
['apple', 'pear', {}, 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", [], "banana"]))
['apple', 'pear', {}, 'lemon', [], 'banana']
>>> list(uniq(["apple", "pear", {}, "lemon", {}, "banana"]))
['apple', 'pear', {}, 'lemon', 'banana']
Это, таким образом, фильтр уникальности, который может работать на любом итерабельном и отфильтровывать uniques, независимо от того, являются ли они хешируемыми или нет.
Он делает одно предположение: если один объект хешируется, а другой нет, два объекта никогда не будут равны. Это может произойти строго, хотя это было бы очень редко.
frozenset
является хэшируемым, set
- нет, и если они имеют одинаковые значения, они равны, но в этом коде они будут рассматриваться как неравные.
set(..)
это просто не будет работать вообще, а при использовании list
это приведет к линейному времени поиска. Таким образом, это подразумевается как «лучший» набор, но с некоторыми подводными камнями.
Если вы не заботитесь о порядке и хотите чего-то другого, чем предлагаемые выше питонические способы (то есть его можно использовать в интервью), то:
def remove_dup(arr):
size = len(arr)
j = 0 # To store index of next unique element
for i in range(0, size-1):
# If current element is not equal
# to next element then store that
# current element
if(arr[i] != arr[i+1]):
arr[j] = arr[i]
j+=1
arr[j] = arr[size-1] # Store the last element as whether it is unique or repeated, it hasn't stored previously
return arr[0:j+1]
if __name__ == '__main__':
arr = [10, 10, 1, 1, 1, 3, 3, 4, 5, 6, 7, 8, 8, 9]
print(remove_dup(sorted(arr)))
Сложность времени: O (n)
Вспомогательное пространство: O (n)
Ссылка: http://www.geeksforgeeks.org/remove-duplicates-sorted-array/
def remove_duplicates(A):
[A.pop(count) for count,elem in enumerate(A) if A.count(elem)!=1]
return A
Компиляция списка для удаления дубликатов
Вы можете сделать это просто с помощью наборов.
Шаг1: Получить различные элементы списков
Шаг2 Получить общие элементы списков
Шаг 3 Объедините их
In [1]: a = ["apples", "bananas", "cucumbers"]
In [2]: b = ["pears", "apples", "watermelons"]
In [3]: set(a).symmetric_difference(b).union(set(a).intersection(b))
Out[3]: {'apples', 'bananas', 'cucumbers', 'pears', 'watermelons'}
Чтобы удалить дубликаты, сделайте это SET, а затем снова создайте LIST и распечатайте/используйте его. У набора гарантировано наличие уникальных элементов. Например:
a = [1,2,3,4,5,9,11,15]
b = [4,5,6,7,8]
c=a+b
print c
print list(set(c)) #one line for getting unique elements of c
Выход будет выглядеть следующим образом (отмечено в python 2.7)
[1, 2, 3, 4, 5, 9, 11, 15, 4, 5, 6, 7, 8] #simple list addition with duplicates
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15] #duplicates removed!!
Иногда вам нужно удалить дубликаты на месте, не создавая новый список. Например, список большой или оставьте его как теневую копию
from collections import Counter
cntDict = Counter(t)
for item,cnt in cntDict.items():
for _ in range(cnt-1):
t.remove(item)
Python имеет множество встроенных функций. Вы можете использовать set(), чтобы удалить дубликаты из списка. Согласно вашему примеру ниже есть два списка t и t2
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
result = list(set(t) - set(t2))
result
Ответ: ['b']
это просто читаемая функция, легко понятная, и я использовал структуру данных dict, я использовал несколько встроенных функций и улучшил сложность O (n)
def undup(dup_list):
b={}
for i in dup_list:
b.update({i:1})
return b.keys()
a=["a",'b','a']
print undup(a)
Отказ от ответственности: вы можете получить ошибку отступа (если скопировать и вставить), используйте приведенный выше код с правильным отступом перед вставкой
К несчастью. Большинство ответов здесь либо не сохраняют порядок, либо являются слишком длинными. Вот простой, сохраняющий порядок ответ.
s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]
[x.append(i) for i in s if i not in x]
print(x)
Это даст вам х с удаленными дубликатами, но с сохранением порядка.
list_with_unique_items = list(set(list_with_duplicates))
def remove_duplicates(input_list):
if input_list == []:
return []
#sort list from smallest to largest
input_list=sorted(input_list)
#initialize ouput list with first element of the sorted input list
output_list = [input_list[0]]
for item in input_list:
if item >output_list[-1]:
output_list.append(item)
return output_list
Для этого требуется установка стороннего модуля, но пакет iteration_utilities
содержит функцию unique_everseen
1, которая может удалять все дубликаты при сохранении порядка:
>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen(['a', 'b', 'c', 'd'] + ['a', 'c', 'd']))
['a', 'b', 'c', 'd']
Если вы хотите избежать накладных расходов на операцию добавления списка, вы можете вместо этого использовать itertools.chain
:
>>> from itertools import chain
>>> list(unique_everseen(chain(['a', 'b', 'c', 'd'], ['a', 'c', 'd'])))
['a', 'b', 'c', 'd']
unique_everseen
также работает, если в списках есть неумелые элементы (например, списки):
>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen([['a'], ['b'], 'c', 'd'] + ['a', 'c', 'd']))
[['a'], ['b'], 'c', 'd', 'a']
Однако это будет (намного) медленнее, чем если элементы хешируются.
1 Раскрытие информации: Я являюсь автором iteration_utilities
-library.