Вывести повторяющиеся значения списка (вопрос по конкретному методу решения)

Чуть больше месяца изучаю 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 шт):

Автор решения: MBo
 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))
→ Ссылка
Автор решения: HardTaker

Я могу предложить вам немного другой способ решения:

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)   
→ Ссылка
Автор решения: vadim vaduxa

При больших значениях 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)
→ Ссылка