Видаліть та витягніть повторювані елементи зі списку (масиву) у Python

Бізнес

У цьому розділі описано, як створити новий список у Python шляхом видалення або вилучення повторюваних елементів зі списку (масиву).

Тут описано наступні деталі.

  • Видаліть повторювані елементи та створіть нові списки
    • Не зберігайте порядок вихідного списку:set()
    • Зберігає порядок вихідного списку:dict.fromkeys(),sorted()
    • Двовимірний масив (список списків)
  • Витягніть повторювані елементи та створіть новий список
    • Не зберігайте порядок вихідного списку
    • Зберігає порядок вихідного списку
    • Двовимірний масив (список списків)

Таку ж концепцію можна застосувати до кортежів замість списків.

Дивіться наступну статтю для

  • Якщо ви хочете визначити, чи містить список або кортеж повторювані елементи
  • Якщо ви хочете витягти елементи, які є загальними чи не спільними для кількох списків замість одного списку

Зауважте, що списки можуть зберігати різні типи даних і суворо відрізняються від масивів. Якщо ви хочете обробляти масиви в процесах, які вимагають розміру пам’яті та адрес пам’яті або чисельної обробки великих даних, використовуйте масив (стандартна бібліотека) або NumPy.

Видаліть повторювані елементи та створіть нові списки

Не зберігайте порядок вихідного списку: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]

Звичайно, його також можна залишити як налаштований. Перегляньте наступну статтю для отримання додаткової інформації про набір типу набору.

Зберігає порядок вихідного списку:dict.fromkeys(),sorted()

Якщо ви хочете зберегти порядок вихідного списку, скористайтеся методом класу fromkeys() типу словника або вбудованою функцією 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() для ключа аргументу sorted, який повертає відсортований список елементів.

index() — це метод, який повертає індекс значення (номер елемента в списку), який можна вказати як ключ sorted() для сортування списку на основі порядку вихідного списку. Ключ аргументу вказується як викликаний (викликаний) об’єкт, тому не пишіть ().

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

Двовимірний масив (список списків)

Для двовимірних масивів (списків списків) метод, що використовує set() або dict.fromkeys(), призводить до помилки типу.

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'

Це пов’язано з тим, що нехешовані об’єкти, такі як списки, не можуть бути елементами набору типів або ключами типу 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” є хибним в оцінці короткого замикання оператора і, то Y не оцінюється (не виконується).
  • Метод append() повертає None.

Якщо елементи вихідного списку seq не існують у побаченому, обчислюються then і after.
seen.append(x) виконується, і елемент додається до seen.
Оскільки метод append() повертає None, а None є False, not seen.append(x) має значення True.
Умовний вираз у нотації для розуміння списку стає True і додається як елемент остаточного створеного списку.

Якщо елементи вихідного списку seq присутні в seen, то x not in 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'