Невозможно создать дублирующийся список из существующего списка, используя понимание списка с условием if - PullRequest
0 голосов
/ 05 июля 2018

У меня есть отсортированный список с дублирующимися элементами, такими как

>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]

Мне нужно создать список, который удаляет смежные дубликаты элементов. Я могу сделать это как:

>>>> dupList = []
     for num in nums:
       if num not in dupList:
         dupList.append(num)

Но я хочу сделать это с пониманием списка. Я попробовал следующий код:

>>> newList = []
>>> newList = [num for num in randList if num not in newList]

Но я получаю результат, как будто условие if не работает.

>>> newList
[1, 2, 2, 3, 4, 4, 5]

Любая помощь будет оценена. Спасибо!!

Редактировать 1: формулировка вопроса, кажется, вводит в заблуждение, учитывая предоставленные мною данные. Цикл for, который я использую, удалит все дубликаты, но поскольку я сортирую список заранее, это не должно быть проблемой при удалении смежных дубликатов.

Ответы [ 7 ]

0 голосов
/ 05 июля 2018

Поскольку ваш список отсортирован, использование set будет быстрым способом достижения вашей цели, следующим образом:

>>> randList = [1, 2, 2, 3, 4, 4, 5]
>>> randList
[1, 2, 2, 3, 4, 4, 5]
>>> remove_dup_list = list(set(randList))
>>> remove_dup_list
[1, 2, 3, 4, 5]
>>> 
0 голосов
/ 05 июля 2018

Python сначала оценивает понимание списка, а затем присваивает его newList , поэтому вы не можете обращаться к нему во время выполнения понимания списка.

Вы можете удалить дубликаты двумя способами: -
1. Использование для цикла

rand_list = [1,2,2,3,3,4,5]
new_list=[]
for i in rand_list:
    if i not in new_list:
        new_list.append(i)
  1. Преобразование списка в набор, затем снова преобразование набора в список и, наконец, сортировка нового списка.
    Поскольку набор сохраняет значения в любом порядке, поэтому при преобразовании набора в список необходимо отсортировать список, чтобы получить элемент в порядке возрастания

    rand_list = [1,2,2,3,3,4,5] sets = set(rand_list) new_list = list(sets) new_list.sort()

0 голосов
/ 05 июля 2018

Мне нужно создать список, который удаляет смежные дубликаты элементов

Обратите внимание, что ваше решение на основе цикла for удалит ВСЕ дубликаты, а не только соседние. Проверьте это с помощью:

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

согласно вашей спецификации результат должен быть:

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

но вы получите

[1, 2, 3, 4, 5]

вместо.

Рабочим решением для удаления только смежных дубликатов является использование генератора:

def dedup_adjacent(seq):
    prev = seq[0]
    yield prev
    for current in seq[1:]:
        if current == prev:
            continue
        yield current
        prev = current

rand_list = [1, 2, 2, 3, 4, 4, 2, 5, 1]
list(dedup_adjacent(rand_list))

=> [1, 2, 3, 4, 2, 5, 1] ​​

0 голосов
/ 05 июля 2018

Вы не можете получить доступ к элементам в списке понимания, как вы идете вперед. Элементы в понимании списка доступны только после завершения понимания.

Для больших списков проверка на членство в списке будет дорогой, хотя и с минимальными требованиями к памяти. Вместо этого вы можете добавить к set:

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

def gen_values(L):
    seen = set()
    for i in L:
        if i not in seen:
            seen.add(i)
            yield i

print(list(gen_values(randList)))

[1, 2, 3, 4, 5]

Этот алгоритм был реализован в сторонней библиотеке toolz. Он также известен как рецепт unique_everseen в документах itertools:

from toolz import unique

res = list(unique(randList))
0 голосов
/ 05 июля 2018

Обновление: сравнение разных подходов

Существуют три способа достижения цели удаления соседних повторяющихся элементов в отсортированном списке, то есть удаления всех дубликатов:

  • с использованием groupby (только смежные элементы, требуется начальная сортировка)
  • с использованием OrderedDict (все дубликаты удалены)
  • с использованием sorted(list(set(_))) (все дубликаты удалены, порядок восстановлен путем сортировки).

Я сравнил время выполнения различных решений, используя:

from timeit import timeit

print('groupby:', timeit('from itertools import groupby; l = [x // 5 for x in range(1000)]; [k for k, _ in groupby(l)]'))
print('OrderedDict:', timeit('from collections import OrderedDict; l = [x // 5 for x in range(1000)]; list(OrderedDict.fromkeys(l))'))
print('Set:', timeit('l = [x // 5 for x in range(1000)]; sorted(list(set(l)))'))

> groupby: 78.83623623599942
> OrderedDict: 94.54144410200024
> Set: 65.60372123999969

Обратите внимание, что подход set является самым быстрым среди всех альтернатив.

Старый ответ

Python сначала оценивает понимание списка, а затем присваивает его newList, поэтому вы не можете обратиться к нему во время выполнения понимания списка. Для иллюстрации рассмотрим следующий код:

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

newList = []
newList = [num for num in randList if print(newList)]

> []
> []
> []
> …

Это становится еще более очевидным, если вы попытаетесь:

# Do not initialize newList2
newList2 = [num for num in randList if print(newList2)]

> NameError: name 'newList2' is not defined

Вы можете удалить дубликаты, превратив randList в набор:

sorted(list(set(randlist)))

> [1, 2, 3, 4, 5]

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

edit : добавлено предложение sorted относительно спецификации требуемого заказа.

0 голосов
/ 05 июля 2018

Использование itertools.groupby - самый простой подход для удаления смежных (и только смежных) дубликатов, даже для несортированного ввода:

>>> from itertools import groupby
>>> [k for k, _ in groupby(randList)]
[1, 2, 3, 4, 5]

Удаление всех дубликатов при сохранении порядка появления может быть эффективно достигнуто с помощью OrderedDict. Это также работает для упорядоченного и неупорядоченного ввода:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(randList))
[1, 2, 3, 4, 5]
0 голосов
/ 05 июля 2018

В этой строке newList = [num for num in randList if num not in newList] сначала будет создан list с правой стороны, затем он будет присвоен newList. Вот почему каждый раз, когда вы проверяете if num not in newList, возвращается True. Becasue newList остается пустым до назначения.

Вы можете попробовать это:

randList = [1, 2, 2, 3, 4, 4, 5]
new_list=[]
for i in randList:
    if i not in new_list:
        new_list.append(i)

print(new_list)
...