Продолжаем работать со списками.
Разберем задания, которые (должны) были вызвать у вас трудности. Напомню, что в данный момент мы работаем с числовыми списками.
Для создания списка, заполненного случайными значениями, удобно использовать такой прием:
a = [rnd(10) for x in range(15)] print(a)
А теперь попробуем удалить все нули. Вариант с использованием count и remove мы рассматривать не будем, надеюсь с ним все понятно. Предположим, что этих функций нет, или мы не можем их использовать. Чтобы удалить все нули нужно, во-первых, перебирать список по номерам, а не по значениям, т.е. использовать цикл вида:
for i in range(len(a)): print(a[i])
Сравним с циклом, который перебирает по значениям:
for x in a: print(x)
Второй способ короче, элегантнее и понятнее. Но он не всегда может быть использован. Есть особенности, с которыми мы разберемся чуть позже, пока вам придется поверить, что оба варианта имею право на существование и понимать и использовать нужно оба варианта перебора. Если вам нужна позиция (номер) элемента, если вам нужно сравнивать с соседними, то подходит только перебор по номерам.
Это было «во-первых». «Во-вторых» видим проблему:
for i in range(len(a)): if a[i] == 0: a.pop(i)
Такой вариант приводит к возникновению ошибки out of range. Запомните и ошибку и причину ее вызывшую. Это выход за пределы списка. Разберем подробнее, что происходит при выполнении: for i in range(12)?
Создается последовательность (0,1,2,3,4,5,6,7,8,9,10,11) и i начинает брать значения из этой последовательности по-очереди. Никакого изменения этой последовательности не предусмотрено! Т.е. после удаления элементов последовательность номеров оказывается длинее, чем последовательность элементов!
И это неизбежно приводит к тому, что вы пытаетесь обратится к элементу, которого не существует.
Попробуем использовать цикл while:
i = 0 while i < len(a): if a[i] == 0: a.pop(i) i += 1
Теперь выхода за пределы списка не будет. Правда нули удаляются не все, но от одной ошибки мы уже избавились. Посмотрим, почему нули удаляются не все, допустим, у вас есть список:
1 0 0 2 3 4
Тогда программа отработает так:
i 1 0 0 2 3 4 (не ноль) i 1 0 0 2 3 4 (ноль, удалить и перейти дальше!) i 1 0 2 3 4
После удаления нуля, следующий элемент «подтягивается» на это место. Нельзя уходить, надо снова проверять.
i = 0 while i < len(a): if a[i] == 0: a.pop(i) else: i += 1
Теперь будет работать нормально, потому что переход на следующую позицию мы делаем только тогда, когда не удаляли. Если удаляли, то проверяем, что там «приползло».
Это хороший способ, но есть лучше!
Попробуйте пройти циклом for c конца!
for i in range(len(a)-1,-1,-1): if a[i] == 0: a.pop(i)
Разве это не прекрасно?
Длина списка изменяется, элементы перемещаются, но это уже не наша проблема!
Есть способ и еще проще:
a = [x for x in a if x != 0]
Или его явная разновидность:
b = [] for x in a: if x != 0: b += [x] a = b print(a)
У всех способов есть свои особенности. Поэтому проще всего знать и понимать все.
2. Удалить все отрицательные
3. Удалить все элементы, которые больше 5
4*. Удалить все элементы, которые меньше своих обоих соседей
А еще попробуйте вернуться к заданиям двух предыдущих уроков и выполнить их.
На следующем уроке мы еще поработаем с числовым списком, чтобы через урок вернуться к «кружочкам». Нам предстоит искать самые большие, самые маленькие и работать с соседями (элементов).
Удачи, жду вопросов в комментариях (в «обычных», т.к. уведомление приходит только о них)
One thought on “25. Работаем со списками в Python (удалять лучше с конца)”