Как удалить повторяющиеся целые числа из списка, чтобы получить список уникальных чисел в Python
Что проверяют
Знает ли кандидат про множества, помнит ли, что они не сохраняют порядок и требуют хешируемости, и умеет ли оценить сложность своего решения.
Как отвечать
Порядок не важен, нужен только набор уникальных значений:
unique = list(set(numbers))Порядок важен, а на практике это чаще всего так:
unique = list(dict.fromkeys(numbers))Начиная с Python 3.7 обычный dict гарантирует порядок вставки на уровне языка, поэтому collections.OrderedDict здесь уже не нужен.
Явный вариант, если просят показать алгоритм:
def dedup(items):
seen = set()
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return resultСложность у всех трёх вариантов линейная по времени в среднем и линейная по дополнительной памяти: проверка вхождения в множество идёт через хеш-таблицу за константу. Наивный вариант с if item not in result даёт квадратичную сложность, и на списке в сто тысяч элементов разница уже измеряется минутами.
Ограничения, которые стоит проговорить сразу:
- элементы должны быть хешируемыми: список или словарь в
setне положить, для них подойдёт сортировка сitertools.groupbyили дедупликация по вычисленному ключу; - множество схлопывает значения, равные по
__eq__и с одинаковым__hash__, поэтому1,1.0иTrueокажутся одним элементом; - порядок обхода
setне случаен, но и не является контрактом: ждать отlist(set(numbers))возрастающей последовательности нельзя. Для маленьких целых так выходит из-за устройства хеширования, а не потому что так задумано.
Если нужен отсортированный результат, это отдельная операция: sorted(set(numbers)) со сложностью n log n.
Где спотыкаются
Обещают, что list(set(x)) вернёт элементы в исходном или возрастающем порядке, и на вопрос про сохранение порядка вспоминают только OrderedDict.fromkeys, забыв, что обычный словарь давно делает то же самое и короче.