Вывести повторяющиеся значения списка (вопрос по конкретному методу решения)
Чуть больше месяца изучаю Python, по учебникам, youtube и онлайн-урокам. Мой вопрос по задаче, решение которой я видел (возможно, один и тот же курс). Но там она решена другими способами. В данном случае хотел бы узнать что не так с моим решением. По ощущениям, логика решения верна, но надо убрать одну ошибку.
Условие: напишите программу, которая принимает на вход список чисел в одной строке и выводит на экран в одну строку значения, которые встречаются в нём более одного раза. Выводимые числа не должны повторяться, порядок их вывода может быть произвольным. Например, если на входе дано: 4 8 0 3 4 2 0 3, на выходе должно быть: 0 3 4.
Мое решение:
a = [int(j) for j in input().split()]
a.sort() # сортировка
b = [] # новый пустой список
for i in range(len(a) - 1):
if a[i] == a[i + 1] % len(a): # если равны два соседних члена списка...
b.append(a[i]) # первый из них переносим в новый список.
while a[i] == a[i + 1]: # и удаляем одинаковые значения чтобы не было повтора
a.pop(a[i])
else:
continue
print(*b, end=' ')
Итак, главная загвоздка - вывести повторяющиеся значения один раз. Т.е. после переноса a[i] в новый список другие равные ему числа удаляются до тех пор, пока к сравнению не будет подано новое число. Часть кода a[i + 1] % len(a) оформил таким образом, чтобы остановить цикл на предпоследнем члене списка (нашел способ в разборе чужого решения). Для этого же выше применял range(len(a) - 1). Тем не менее, для строки с while регулярно выводится ошибка 'IndexError: list index out of range'.
Знаю, что можно решить ее в две строчки, может даже в одну. Но сейчас мне важнее на примере этого решения найти изъян в собственной логике.
Ответы (3 шт):
a[i + 1] % len(a)
не имеет смысла. Вы понимаете, что там могло делаться? Вот что:
a[(i + 1) % len(a)]
но вам это всё равно не нужно, т.е. диапазон ограничен
Вы меняете список, по которому итерируетесь, так делать нельзя.
И здесь запросто выходите за границу списка, если удалили весь хвост.
while a[i] == a[i + 1]:
a.pop(a[i])
А
else:
continue
просто не нужно.
Давайте сделаем так - будем проверять левый и правый элементы, таким образом из длинной серии условие сработает только на последней паре. И предусмотрим аккуратную проверку для последнего элемента. И удалять ничего не надо. (Можно превратить в однострочник, но незачем)
for i in range(1, len(a)):
if a[i] == a[i - 1] and (i + 1 == len(a) or a[i] != a[i + 1]):
print(a[i], end=' ')
Добавлю линейный алгоритм
from collections import Counter
c = Counter([4, 8, 0, 3, 4, 2, 0, 3])
for k in c:
if c[k]>1:
print(k)
или однострочником
print(" ".join(str(k) for k, v in Counter([4, 8, 0, 3, 4, 2, 0, 3]).items() if v > 1))
Я могу предложить вам немного другой способ решения:
a = [int(j) for j in input().split()] #создаём 2 списка
b = []
for i in range(len(a)):
for j in range(i+1, len(a)):
if a[i] == a[j] and a[i] not in b:
b.append(a[i])
print(*b)
При больших значениях a этот вариант может быть быстрее Counter
import random
a = [random.randint(-10000000, 10000000) for _ in range(5000000)]
s, b = set(), set()
for n in a:
(b if n in s else s).add(n)
print(*b)