[ Сборник задач ]
Тема 10. Работа с циклами

[ Сборник задач ]
Тема 10. Работа с циклами

Python Workbook Cover T1
Операторы: for, while
Контент: Вопросы (5шт) + задачи (5шт)

Оглавление

1
Введение
Определение циклов (loops) и их структура в языке Python, особенности использования, различия. Конструкции прерывания циклов глобально и на уровне конкретной итерации (continue, break). Инструменты, заменяющие циклы.
Перейти
2
Вопросы и ответы
5 вопросов по теме "Работа с циклами" + ответы
Перейти
3
Условия задач
5 задач по теме двух уровней сложности: Базовый и *Продвинутый
Перейти
4
Решения задач
Приводим код решений указанных выше задач
Перейти
1
One

Введение

В языке программирования Python циклы существенно проще и яснее для понимания, нежели в ряде других. Некоторые языки предоставляют 3-5 конструкций циклов, иные – и вовсе не имеют таких структур (ряд чисто функциональных языков программирования). В Питоне имеется только два типа циклов: while и for.
1. Конструкция цикла while
while <выражение истинно>:
    <осуществление операций>
else:
    <обработается только при несрабатывании инструкции «break»>
2. Конструкция цикла for
for <перебор итерируемого объекта>:
    <осуществление операций над каждым элементом>
else:
    <обработается только при несрабатывании инструкции «break»>
Цикл for позволяет перебирать элементы по индексу или напрямую.

Оба вида циклических структур могут включать условные выражения и специальные «прерыватели»: continue, break.

Для успешного решения заданий необходимо понимать устройство циклов в Python, уметь использовать вложенные циклы, стремиться минимизировать количество итераций (при такой возможности).

Читайте также

2
Two

Вопросы по теме "Работа с циклами"

1. В чем основное отличие циклов for и while?
Несмотря на то, что и for и while необходимы для повторения некоего количества раз одной и той же операции , циклы отличаются друг от друга и имеют свою специфику. Даже с учетом их формальной взаимозаменяемости.

While удобен тогда, когда повторяющаяся операция проводится до тех пор, пока условие верно, т.е. возвращает True. Отсюда возможна ситуация, когда цикл не сработает ни разу либо будет повторяться бесконечно. Чтобы была возможность применить данный вид цикла для объекта, тот обязан иметь атрибут __bool__().

Цикл for применяется для последовательного манипулирования с элементами итератора. Другими словами, он проходит по очереди элементы объекта (например, списка) и заканчивается (в общем случае) после их полного перебора.

Таким образом, for удобен для перебора, а while – проверки истинности условия перед каждой итерацией.
2. Приведите пример бесконечного цикла. Применяется ли он на практике?
Проще всего бесконечный цикл привести на примере цикла while. Так как он проверяет истинность условия, то его искусственно можно сделать таковым всегда.

Пример – Интерактивный режим
----
>>> while True:
... x = 10


Вместо явного указания True можно использовать любую комбинацию, результирующую в истинность (например, 1 + 1 == 2, 7 > 5, bool('Python') и т.п.)

Любой код, написанный после данного цикла, не будет достигнут.

Инструкция for редко приводит к возникновению бесконечных циклов. Правда, и ее возможно принудить к бесконечному выполнению.

Пример – Интерактивный режим
----
>>> from itertools import count
>>> for number in count():
... number += 7


Функция count() последовательно выводит все числа от 1 до бесконечности с шагом 1 (т.е. 1, 2, 3, 4…) по умолчанию.

Может показаться, что бесконечные циклы никому не нужны. Однако, они достаточно часто применяются (например, окно программы, которое будет показываться до тех пор, пока вы его принудительно не закроете).
3. Сработает ли инструкция else в нижеследующем примере? Поясните ответ.

Пример – IDE
----
for letter in 'программист':
____if letter == 'П':
________break
else:
____print('Перебор букв в слове закончен')

Как известно, инструкция else в циклах срабатывает только в том случае, когда цикл не прерван командой break. В нашем примере имеется данная команда. Тем не менее, в слове программист были перебраны все буквы и не найдена заглавная П, которая бы его прервала.

Поэтому ответ очевиден: else сработает. Проверим.

Пример – Интерактивный режим
----
>>> for letter in 'программист':
... if letter == 'П':
... break
... else:
... print('Перебор букв в слове закончен')
...
Перебор букв в слове закончен

4. Какова вычислительная сложность цикла for, перебирающего элементы множества (сколько нужно совершить операций)?
При исполнении поставленных перед программистом задач важно понимать вычислительную сложность предлагаемого алгоритма решения. Ведь зачастую может случиться так, что алгоритм решения неэффективен (занимает неприемлемое количество времени или операций).

Для этого приходится определять сложность решения «О большое» (асимптотическая нотация, нотация Бахмана-Ландау). Это позволяет понять, насколько оптимален алгоритм.

Так, при переборе элементов множества через цикл for в худшем случае потребуется пройтись по каждому из них. Следовательно, необходимо осуществить количество операций, равное размеру объекта.

В обозначениях асимптотической нотации это выглядит так: O(n), где n – размер множества.
5*. Замените цикл for в примере ниже на 2 другие структуры (представьте, что for в классическом виде использовать нельзя, но код должен вернуть требуемый результат).

Пример – IDE
-----
lst = [2, 4, 5, 8, 9, 13]
for number in range(len(lst)):
____lst[number] *= number
print(lst)


Результат выполнения
---
[0, 4, 10, 24, 36, 65]
Как видно из задания, нам требуется создать новый список, в котором каждое число умножается на его индекс.

Цикл for в приведенном примере легко заменяется списковым включением или функцией map.


1 - Списковое включение

Пример – IDE
----
lst = [2, 4, 5, 8, 9, 13]
lst = [lst[number] * number for number in range(len(lst))]
print(lst)

Результат выполнения
----
[0, 4, 10, 24, 36, 65]
2 – Функция map()



2 – Функция map()

Пример – IDE
----
lst = [2, 4, 5, 8, 9, 13]
lst = list(map(lambda number: number * lst.index(number), lst))
print(lst)

Результат выполнения
----
[0, 4, 10, 24, 36, 65]
3
Three

Задачи по теме "Работа с циклами"

Задача 3
Анна решила представить некую таблицу с заглавными и строчными буквами русского алфавита в красивом формате. Об этом ее попросили англоязычные друзья из социальных сетей.

Недолго думая девушка создала скрипт, который выполнял подобную операцию. Результат работы программы продемонстрирован ниже. Сможете повторить (в строках с галочками - их 27 штук, чтобы вам не пришлось долго считать)? Для идентичности результатов примените любой моноширинный шрифт (в котором все символы имеют одинаковую ширину).

^^^^^^^^^^^^^^^^^^^^^^^^^^^
| А а || К к || Х х |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Б б || Л л || Ц ц |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| В в || М м || Ч ч |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Г г || Н н || Ш ш |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Д д || О о || Щ щ |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Е е || П п || Ъ ъ |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Ё ё || Р р || Ы ы |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Ж ж || С с || Ь ь |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| З з || Т т || Э э |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| И и || У у || Ю ю |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Й й || Ф ф || Я я |
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Решение
Задача 4
Для идентификации своего круга проверенных лиц будущий тайный агент (ведь все о чем-то мечтают) Максим решил пускать на свою страничку в Интернете только тех, чьи никнеймы есть в его секретном списке. Он уверен в своих людях (особенно в том, что они по глупости не расскажут никому своё секретное прозвище), как и в том, что имена товарищей невозможно подобрать случайно.

К слову, вот этот список: Мавпродош, Лорнектиф, Древерол, Фиригарпиг, Клодобродыч. По мере увеличения круга знакомых Максим, естественно, дополнит данный список.

Ваша задача такова: повторите код, который будет спрашивать у пользователя его ник и либо пускать на сайт (выведется сообщение Ты – свой. Приветствую, любезный {НИК_ПОСЕТИТЕЛЯ}!), либо нет (в этом случае будет такой текст: Тут ничего нет. Еще есть вопросы?. Фактически, будущий супергерой решил поиздеваться над теми, кого нет в его удивительном перечне, так как им будет показываться это сообщение постоянно. Очень коварный замысел!).

Для проверки прозвищ посетителей используйте встроенную функцию input().
Решение
4
Two

Решения

Задача 1. Базовый уровень

Условие
На вход функция more_than_five(lst) получает список из целых чисел. 
Результатом работы функции должен стать новый список, в котором содержатся только те числа, которые больше 5 по модулю.
Для решения задачи воспользуемся циклом for.
Пример – IDE
def more_than_five(lst):
	new_lst = []
	for number in lst:
    	if abs(number) > 5:
        	new_lst.append(number)
	return new_lst
 
 
# Тесты
print(more_than_five([-11, 4, -2, 90, 400, 0, -5]))
print(more_than_five([-2, 2, 3, 4, 0, -1]))
print(more_than_five([70, -900, 41, 0]))
Результат выполнения
[-11, 90, 400]
[]
[70, -900, 41]

Задача 2. Базовый уровень

Условие
Евгению предоставили строку, состоящую из русских букв разных регистров, и попросили очистить ее от заглавных литер. 
Как ему показалось, он написал верный код, но результат совсем не порадовал. 
Ниже представлен пример работы «чистильщика строк», которому срочно требуется ваша помощь.
 
Пример – IDE
---- 
letters = 'ЫгВЫоЯСремДШНККАыкЩЙФа'

for letter in letters:
____if letter.upper() = letters:
________letters.replace(letter, '')

print(letters)
Если запустить код Евгения, то получаем синтаксическую ошибку. Вот уж действительно горе-ученик.

Что ж, давайте думать, что нужно исправить:
- в условии if явно не хватает второго знака равно, так как мы не присваиваем переменную, а проверяем ее истинность;
– каждую букву в верхнем регистре нужно сравнивать не со всем набором символом, а с одним знаком;
- заменяя буквы на пустые символы мы создаем новую строку, которую никак не сохраняем. В итоге изначальный объект не поменяется. Нужно создать пустую строку и дополнять ее верными символами, пропуская ненужные. А раз требуется сохранить прежнее название строки, то мы переприсвоим исходной вновь полученную.
Пример - IDE
letters = 'ЫгВЫоЯСремДШНККАыкЩЙФа'
clean_string = ''
for letter in letters:
    if not letter.isupper():
        clean_string += letter
letters = clean_string
print(letters)
Результат выполнения
горемыка

Задача 3. Базовый уровень

Условие
Анна решила представить некую таблицу с заглавными и строчными буквами русского алфавита в красивом формате. 
Об этом ее попросили англоязычные друзья из социальных сетей.

Недолго думая девушка создала скрипт, который выполнял подобную операцию. 
Результат работы программы продемонстрирован ниже. 
Сможете повторить (в строках с галочками - их 27 штук, чтобы вам не пришлось долго считать)? Для идентичности результатов примените любой моноширинный шрифт (в котором все символы имеют одинаковую ширину).
 
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  А а  ||  К к  ||  Х х  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Б б  ||  Л л  ||  Ц ц  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  В в  ||  М м  ||  Ч ч  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Г г  ||  Н н  ||  Ш ш  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Д д  ||  О о  ||  Щ щ  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Е е  ||  П п  ||  Ъ ъ  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Ё ё  ||  Р р  ||  Ы ы  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Ж ж  ||  С с  ||  Ь ь  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  З з  ||  Т т  ||  Э э  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  И и  ||  У у  ||  Ю ю  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Й й  ||  Ф ф  ||  Я я  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
В идеале требуется провести минимум «издевательств» над входящими данными (т.е. над алфавитом). В нашем случае мы просто записали все буквы русского алфавита в строку.

Также, в задаче требовалось понять алгоритм разбиения знаков на 3 столбца.
Пример – IDE
rus_lower = 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
for position in range(11):
    print('^' * 27)
    for letter in rus_lower:
        if rus_lower.index(letter) % 11 == position:
            print('| ', letter.upper(), letter, ' |', end='')
    print()
print('^' * 27)
Результат выполнения
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  А а  ||  К к  ||  Х х  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Б б  ||  Л л  ||  Ц ц  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  В в  ||  М м  ||  Ч ч  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Г г  ||  Н н  ||  Ш ш  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Д д  ||  О о  ||  Щ щ  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Е е  ||  П п  ||  Ъ ъ  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Ё ё  ||  Р р  ||  Ы ы  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Ж ж  ||  С с  ||  Ь ь  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  З з  ||  Т т  ||  Э э  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  И и  ||  У у  ||  Ю ю  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|  Й й  ||  Ф ф  ||  Я я  |
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Задача 4. Базовый уровень

Условие
Для идентификации своего круга проверенных лиц будущий тайный агент (ведь все о чем-то мечтают) 
Максим решил пускать на свою страничку в Интернете только тех, чьи никнеймы есть в его секретном списке. 
Он уверен в своих людях (особенно в том, что они по глупости не расскажут никому своё секретное прозвище), 
как и в том, что имена товарищей невозможно подобрать случайно.

К слову, вот этот список: Мавпродош, Лорнектиф, Древерол, Фиригарпиг, Клодобродыч. 
По мере увеличения круга знакомых Максим, естественно, дополнит данный список.

Ваша задача такова: повторите код, который будет спрашивать у пользователя его ник и 
либо пускать на сайт (выведется сообщение «Ты – свой. Приветствую, любезный {НИК_ПОСЕТИТЕЛЯ}!»), 
либо нет (в этом случае будет такой текст: «Тут ничего нет. Еще есть вопросы?». 
Фактически, будущий супергерой решил поиздеваться над теми, кого нет в его удивительном перечне, так как им будет показываться это сообщение постоянно. 
Очень коварный замысел!).

Для проверки прозвищ посетителей используйте встроенную функцию input().
Данное задание удобно решать через while/else.
Пример - IDE
nick = input()
secret_list = ['Мавпродош', 'Лорнектиф', 'Древерол', 'Фиригарпиг', 'Клодобродыч']
 
while nick not in secret_list:
    print('Тут ничего нет. Еще есть вопросы?')
	  nick = input()
else:
	  print(f'Ты – свой. Приветствую, любезный {nick}!')
Результат выполнения
>Агент007
Тут ничего нет. Еще есть вопросы?
>Нету(
Тут ничего нет. Еще есть вопросы?
>ЕСТЬ!!!
Тут ничего нет. Еще есть вопросы?
>Мавпродош
Ты – свой. Приветствую, любезный Мавпродош!

Задача 5. *Продвинутый уровень

Условие
Валентина прогуляла лекцию по математике. 
Преподаватель решил подшутить над нерадивой студенткой и 
попросил ее на практическом занятии перечислить все положительные делители некоторых целых чисел. 
Для несложных примеров студентка быстро нашла решения (для числа 6 это: 1, 2, 3, 6; а для числа 16 это: 1, 2, 4, 8, 16), но этим все не закончилось. 
На домашнее задание ей дали варианты посложнее: 23436, 190187200, 380457890232.

Решить такое вручную, как вы понимаете, практически нереально. 
Вот Валентина и обратилась к вам за помощью. 
Помогите ей (при помощи функции all_divisors(number)). 
Постарайтесь найти самое оптимальное решение. 
Результат представьте в виде списка (не забудьте отсортировать по возрастанию).
Для решения задания важно не просто подойти к делу в лоб. Требуется оптимизация алгоритма для минимизации времени расчета.

Первое, что приходит на ум – простой перебор всех вариантов. Каким бы мощным не был ваш ПК, число в 380 млрд он будет долго итерировать.

Вторая идея – перебрать все числа только до половины искомого числа (и добавить после этого еще и само число в список). Но и этот вариант не особо сокращает время.

Самый оптимальный вариант – перебрать числа до квадратного корня из искомого. Чтобы пояснить решение, приведем пример попроще. Возьмем число 100. Оно делится на 1 и на само себя. Сразу заносим в список очевидный набор. Затем начинаем с двойки и идем по всем возможным числам. 100 делится на 2, его заносим в список, но результат (т.е. 100 : 2 = 50) также является делителем числа 100. Его тоже сразу добавляем. Аналогично поступаем далее, находя пары делителей: (4, 25), (5, 20), (10, 10). Итак, мы дошли до корня квадратного из 100. Число 10 повторяется, поэтому следует его добавить лишь 1 раз. Есть ли смысл идти дальше в поиске делителей? Ведь далее получим такие делители: 20, 25, 50 и 100, но мы их уже занесли в список. Получается, проверка делителей до корня квадратного из любого положительного числа вполне достаточна.
Пример - IDE
def all_divisors(number):
    lst = [1, number]
    for i in range(2, 1 + int(number ** 0.5)):
        if number % i == 0:
            lst.extend({number // i, i})
    return sorted(lst)
 
# Тесты
print(all_divisors(23_436))
print(all_divisors(190_187_200))
print(all_divisors(380_457_890_232))
Результат выполнения
[1, 2, 3, 4, 6, 7, 9, 12, 14, 18, 21, 27, 28, 31, 36, 42, 54, 62, 63, 84, 93, 108, 124, 126, 186, 189, 217, 252, 279, 372, 378, 434, 558, 651, 756, 837, 868, 1116, 1302, 1674, 1953, 2604, 3348, 3906, 5859, 7812, 11718, 23436]
[1, 2, 4, 5, 7, 8, 10, 14, 16, 20, 25, 28, 32, 35, 40, 50, 56, 64, 70, 80, 100, 112, 140, 160, 175, 200, 224, 280, 320, 350, 400, 448, 560, 700, 800, 1120, 1400, 1600, 2240, 2800, 5600, 11200, 16981, 33962, 67924, 84905, 118867, 135848, 169810, 237734, 271696, 339620, 424525, 475468, 543392, 594335, 679240, 849050, 950936, 1086784, 1188670, 1358480, 1698100, 1901872, 2377340, 2716960, 2971675, 3396200, 3803744, 4754680, 5433920, 5943350, 6792400, 7607488, 9509360, 11886700, 13584800, 19018720, 23773400, 27169600, 38037440, 47546800, 95093600, 190187200]
[1, 2, 3, 4, 6, 7, 8, 12, 14, 17, 21, 24, 28, 34, 42, 51, 56, 68, 84, 102, 119, 136, 168, 204, 238, 289, 357, 408, 476, 578, 714, 867, 952, 1156, 1428, 1734, 2023, 2312, 2856, 3468, 4046, 6069, 6936, 8092, 12138, 16184, 24276, 48552, 7836091, 15672182, 23508273, 31344364, 47016546, 54852637, 62688728, 94033092, 109705274, 133213547, 164557911, 188066184, 219410548, 266427094, 329115822, 399640641, 438821096, 532854188, 658231644, 799281282, 932494829, 1065708376, 1316463288, 1598562564, 1864989658, 2264630299, 2797484487, 3197125128, 3729979316, 4529260598, 5594968974, 6793890897, 7459958632, 9058521196, 11189937948, 13587781794, 15852412093, 18117042392, 22379875896, 27175563588, 31704824186, 47557236279, 54351127176, 63409648372, 95114472558, 126819296744, 190228945116, 380457890232]
Как вам материал?

Читайте также