Удаление и извлечение дублирующихся элементов из списка (массива) в Python

Бизнес

В этом разделе описывается, как создать новый список в Python путем удаления или извлечения дублирующихся элементов из списка (массива).

Здесь описаны следующие детали.

  • Удаление дублирующих элементов и создание новых списков
    • Не сохранять порядок оригинального листинга:set()
    • Сохраняет порядок оригинального листинга: dict.fromkeys(),sorted()
    • Двумерный массив (список списков)
  • Извлечение дублирующихся элементов и создание нового списка
    • Не сохранять порядок оригинального листинга
    • Сохраняет порядок оригинального листинга
    • Двумерный массив (список списков)

Та же концепция может быть применена к кортежам вместо списков.

См. следующую статью для

  • Если вы хотите определить, есть ли в списке или кортеже дублирующиеся элементы
  • Если вы хотите извлечь элементы, которые являются общими или не общими для нескольких объявлений, а не для одного объявления

Обратите внимание, что списки могут хранить различные типы данных и строго отличаются от массивов. Если вы хотите работать с массивами в процессах, где требуется размер памяти и адреса памяти или численная обработка больших данных, используйте array (стандартная библиотека) или NumPy.

Удаление дублирующих элементов и создание новых списков

Не сохранять порядок оригинального листинга: set()

Если нет необходимости сохранять порядок исходного списка, используйте set(), которая генерирует множество типа set.

Тип set — это тип данных, который не имеет дублирующихся элементов. Когда в set() передается список или другой тип данных, дублирующиеся значения игнорируются, и возвращается объект типа set, в котором элементами являются только уникальные значения.

Если вы хотите сделать его кортежем, используйте tuple().

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(set(l))
# {1, 2, 3, 4, 5}

print(list(set(l)))
# [1, 2, 3, 4, 5]

Конечно, его также можно оставить как set. Более подробную информацию о типе set смотрите в следующей статье.

Сохраняет порядок оригинального листинга: dict.fromkeys(),sorted()

Если вы хотите сохранить порядок исходного списка, используйте метод класса fromkeys() типа dictionary или встроенную функцию sorted().

dict.fromkeys() создает новый объект словаря, ключами которого являются списки, кортежи и т.д., указанные в аргументах. Если второй аргумент опущен, то значением будет None.

Поскольку ключи словаря не имеют дублирующихся элементов, дублирующиеся значения игнорируются, как и в set(). Кроме того, объект словаря можно передать в качестве аргумента в list(), чтобы получить список, элементами которого являются ключи словаря.

print(dict.fromkeys(l))
# {3: None, 2: None, 1: None, 5: None, 4: None}

print(list(dict.fromkeys(l)))
# [3, 2, 1, 5, 4]

Начиная с Python 3.7 (CPython — 3.6) гарантируется, что dict.fromkeys() сохраняет порядок последовательности аргументов. В более ранних версиях встроенная функция sorted() использовалась следующим образом.

Укажите метод кортежа списка index() для аргумента key в sorted, который возвращает отсортированный список элементов.

index() — это метод, возвращающий индекс значения (номер элемента в списке), который может быть указан в качестве ключа sorted() для сортировки списка на основе порядка исходного списка. Аргумент key указывается как вызываемый (callable) объект, поэтому не пишите ().

print(sorted(set(l), key=l.index))
# [3, 2, 1, 5, 4]

Двумерный массив (список списков)

Для двумерных массивов (списков списков) метод с использованием set() или dict.fromkeys() приводит к TypeError.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]

# l_2d_unique = list(set(l_2d))
# TypeError: unhashable type: 'list'

# l_2d_unique_order = dict.fromkeys(l_2d)
# TypeError: unhashable type: 'list'

Это связано с тем, что нехешируемые объекты, такие как списки, не могут быть элементами типа set или ключами типа dict.

Определите следующие функции Порядок исходного списка сохраняется и работает для одномерных списков и кортежей.

def get_unique_list(seq):
    seen = []
    return [x for x in seq if x not in seen and not seen.append(x)]

print(get_unique_list(l_2d))
# [[1, 1], [0, 1], [0, 0], [1, 0]]

print(get_unique_list(l))
# [3, 2, 1, 5, 4]

Используется нотация понимания списка.

Здесь мы используем следующее

  • Если X в «X и Y» является ложным при замыкании оценки оператора and, то Y не оценивается (не выполняется).
  • Метод append() возвращает None.

Если элементы исходного списка seq не существуют в seen, то оцениваются then и after.
seen.append(x) выполняется, и элемент добавляется в seen.
Поскольку метод append() возвращает None, а None — это False, not seen.append(x) имеет значение True.
Условное выражение в нотации понимания списка становится True и добавляется как элемент конечного сформированного списка.

Если элементы исходного списка seq присутствуют в seen, то x не в seen — False, а условное выражение для выражения понимания списка — False.
Поэтому они не добавляются как элементы окончательного сформированного списка.

Другой метод — установить ось аргумента в функции NumPy np.unique(), хотя результат будет отсортирован.

Извлечение дублирующихся элементов и создание нового списка

Не сохранять порядок оригинального листинга

Чтобы извлечь из исходного списка только дублирующиеся элементы, используйте collections.Counter().
Возвращает collections.Counter (подкласс словаря) с элементами в качестве ключей и количеством элементов в качестве значений.

import collections

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(collections.Counter(l))
# Counter({3: 3, 2: 2, 1: 2, 5: 1, 4: 1})

Поскольку словарь является подклассом словаря, для извлечения ключей и значений можно использовать функцию items(). Достаточно извлечь ключи, число которых равно двум или более.

print([k for k, v in collections.Counter(l).items() if v > 1])
# [3, 2, 1]

Сохраняет порядок оригинального листинга

Как показано в примере выше, начиная с Python 3.7, ключи collections.Counter сохраняют порядок исходного списка и так далее.

В более ранних версиях достаточно сортировки с помощью sorted(), а также удаления дублирующихся элементов.

print(sorted([k for k, v in collections.Counter(l).items() if v > 1], key=l.index))
# [3, 2, 1]

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

cc = collections.Counter(l)
print([x for x in l if cc[x] > 1])
# [3, 3, 2, 1, 1, 2, 3]

Двумерный массив (список списков)

Для двумерных массивов (списков списков) возможны следующие функции, когда порядок исходного списка не сохраняется и когда он сохраняется, соответственно. Это также работает для одномерных списков и кортежей.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]
def get_duplicate_list(seq):
    seen = []
    return [x for x in seq if not seen.append(x) and seen.count(x) == 2]

def get_duplicate_list_order(seq):
    seen = []
    return [x for x in seq if seq.count(x) > 1 and not seen.append(x) and seen.count(x) == 1]

print(get_duplicate_list(l_2d))
# [[0, 1], [1, 1]]

print(get_duplicate_list_order(l_2d))
# [[1, 1], [0, 1]]

print(get_duplicate_list(l))
# [3, 1, 2]

print(get_duplicate_list_order(l))
# [3, 2, 1]

Если вы хотите извлечь с дубликатами, оставьте элементы из исходного списка с количеством два или более.

print([x for x in l_2d if l_2d.count(x) > 1])
# [[1, 1], [0, 1], [0, 1], [1, 1], [1, 1]]

Обратите внимание, что поскольку вычислительная сложность count() равна O(n), показанная выше функция, которая многократно выполняет count(), очень неэффективна. Возможно, существует более разумный способ.

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

# print(collections.Counter(l_2d))
# TypeError: unhashable type: 'list'
Copied title and URL