Как вставить после каждого однозначного числа такое же в списке 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]
Не надо менять список по которому вы итерируетесь. Почти всегда это кончается плохо. В вашем примере вставляется число и на следующей итерации вы обрабатываете то что вставили. В итоге вместо одного вставляется много элементов, очень много.
Можно исправить на цикл 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]
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)