Как вставить после каждого однозначного числа такое же в списке Python

Дан список

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Нужно после каждого однозначного числа вставить ещё такое же. Пытался сделать так

for key, el in enumerate(lst):
if el < 10:
    lst.insert(key+1, el)
    print(lst)

Но цикл зависает после 1ого элемента, как его перевести на следующий я не понял


Ответы (4 шт):

Автор решения: Никомах
def foo(lst):
    lst2 = [x for x in lst if x < 10]
    return sorted(lst + lst2)

foo([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) # -> [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12]
→ Ссылка
Автор решения: Stanislav Volodarskiy

Не надо менять список по которому вы итерируетесь. Почти всегда это кончается плохо. В вашем примере вставляется число и на следующей итерации вы обрабатываете то что вставили. В итоге вместо одного вставляется много элементов, очень много.

Можно исправить на цикл while и аккуратно обработать изменение индексов в случае вставки:

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

i = 0
while i < len(lst):
    if lst[i] < 10:
        lst.insert(i + 1, lst[i])
        i += 2  # пропустить вставленный элемент и перейти к следующему
    else:
        i += 1  # следующий элемент

print(lst)

Код станет проще если перебирать индексы в обратном порядке:

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

for i in reversed(range(len(lst))):
    if lst[i] < 10:
        lst.insert(i + 1, lst[i])

print(lst)

Оба предыдущих способа страдают медлительностью на длинных списках. Создавать новый список - быстро и просто:

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

lst2 = []
for v in lst:
    if v < 10:
        lst2.append(v)
    lst2.append(v)

print(lst2)

Более питонический способ - создавать новый список генератором:

def duplicate(lst):
    for v in lst:
        if v < 10:
            yield v
        yield v


lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

lst[:] = duplicate(lst) # обновляем старый список на месте

print(lst)

Два последних варианта используют двойную память. А можно решить задачу без дополнительной памяти, как было в двух первых вариантах. И сложность сохранить линейную. Но код будет страшный. Если знаете как сохранить изящный код и получить линейную сложность без дополнительной памяти, напишите. А пока так:

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

k = sum(1 for v in lst if v < 10)
j = len(lst) - 1
i = j + k
lst.extend(range(k))  # подойдёт любая коллекция размера k
while i > j:
    if lst[j] < 10:
        lst[i] = lst[j]
        i -= 1
    lst[i] = lst[j]
    i -= 1
    j -= 1

print(lst)

В этой модификации нет одного индекса и нет дублирования кода - v < 10 в предыдущей версии. Сложность линейная, дополнительной памяти не требуется. Но всё равно один индекс остался и код не самый простой:

def duplicate(seq):
    for v in seq:
        if v < 10:
            yield v
        yield v


lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

k = sum(1 for _ in duplicate(lst))

# важно сохранить итератор до изменения длины списка
it = reversed(lst)

# подойдёт любая коллекция размера k - len(lst)
lst.extend(range(k - len(lst)))

i = k - 1
for v in duplicate(it):
    lst[i] = v
    i -= 1

print(lst)
→ Ссылка
Автор решения: Алексей Р

Вариант с извлечением элементов из первого списка и дополнением второго. Для универсальности добавил обработку отрицательных чисел

lst = [1, 2, 3, 4, 5, 6, -12, -2, 7, 8, 9, 10, 11, 12]
out = []
while lst:
    x = lst.pop(0)
    if 0 <= x < 10:  # знак числа тоже считаем знаком
        out.append(x)
    out.append(x)

print(out)
[1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, -12, -2, 7, 7, 8, 8, 9, 9, 10, 11, 12]
→ Ссылка
Автор решения: Qwertiy

tio.run

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
res = [y for x in a for y in [x] * (1 + (0 <= x <= 9))]
print(res)
→ Ссылка