Как стать автором
Обновить

Как же писать эти грёбаные циклы?

Время на прочтение5 мин
Количество просмотров20K

Когда мои ученики, уже выучив основы синтаксиса языка Python, понимают, что проблема вовсе не в незнании синтаксиса, моё лицо расплывается в самодовольной, но всё же доброй улыбке. Мысль "ну я же говорил" больше не возникает. Повзрослел, видимо, дяденька.

Немного лирики

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

Было бы здорово иметь чёткий алгоритм размышлений, который при знании синтаксиса поможет идеям всплывать в голове. За свою практику я создал много таких алгоритмов, а также позаимствовал у гуру программирования. Большая их часть основана на бытовых аналогиях событий из создаваемой программы. Например, набор переменных можно представить, как конвейерную ленту с коробочками, в каждой из которых - свой товар. Сама коробочка - это и есть переменная, а надпись на неё - её имя. Внутри одной коробочки - число, внутри другой - текст, и т. д.

Задание

Сделаем перерыв в этой лирике и сразу перекинемся на разбор цикла. Положим, имеется список строчных объектов, по смыслу - имена селебрити:

А получить на выходе нужно список из тех же людей, но уже в формате инициалов:

Рассмотри эту задачу с точки зрения самого простого и, в то же время, самого популярного формата "ввод данных ➜ обработка данных ➜ вывод данных". Как вы уже догадались, присвоение переменной celebrities - это ввод данных.

Этапы

В размышлениях над задачами, где, скорее всего, понадобится цикл for, я выделяю 5 этапов (если не учитывать нулевой). Вот они:

  • [этап 0] Понять, что задачу стоит решать именно циклом, и именно циклом for.

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

    В нашем случае на входе - список, что является последовательностью (наряду со строками, словарями, множествами, кортежами, numpy.array'ями, и т. д.), а на выходе - опять же список. Причём, длины их совпадают. Кажется, каждый элемент входного списка напрямую связан с соответственным элементом выходного - так и есть!

    Крайне похоже, что весь процесс разбивается на отдельные повторяющиеся куски одного и того же действия: сконвертировать имя отдельного селебрити и забросить полученный результат в новоиспечённый список.

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

  • этап [1] Определиться, какой конкретно результат должен быть по исходу каждой итерации, и выполнить первые несколько итераций вручную, вообще без цикла.

    В нашем случае, мы делаем всё, чтобы имя одного селебрити превратилось в инициалы и улетело в список, предназаченный для выходных данных. Критерий успешности итерации - в выходном списке последним элементом лежит строка вида "{первая буква имени}.{первая буква фамилии}.".

    Приступим. "Tom Cruise" превращаем в "T.C." любым путём (ведь пока для нас на первом месте - критерий успешности итерации).

Результат получили? Получили! Если вы не совсем новичок, то уже чуете, что так всё конечно же, не останется.

Это была первая итерация грядущего цикла. Проделаем теперь ещё и вторую:

Всё круто. Первый этап пройден.

  • этап [2] Привести итерации к однородному виду.

    Один и тот же результат всегда может быть получен разными путями. Сам результат обычно не несёт с собой информации о том, откуда он взялся. Самый простой пример будет понятен даже людям, далёким от мира программирования: положим, результат - число 11. С точки зрения математики, его могла породить сумма 5 + 6, разность 14 - 3, корень из 121 и куча других действий. Ведь так? И это была лишь арифметика. А если зайти на высшую математику? А если на территорию Python? Ведь команды в Python - это далеко не только вычисления!

    Ключевая команда из нашего алгоритма - это конвертация имени в инициалы:

Она состоит из константной (неизменной) части, и постоянно меняющейся. Чтобы иметь возможность такую "ручную" итерацию превратить в реальную итерацию цикла, все меняющиеся части нужно заменить на неизменные, чаще всего - просто на какие-либо команды. Индексы 4 и -5 - это то, что нам здесь не нравится.

Ну и вариант максимально независимый от конкретных имён из списка:

Теперь намного лучше! Результат - тот же, но теперь каждая итерация более похожа на другую. Мы привели их к однородному виду.

  • этап [3] Выделить группу объектов, которые неизбежно меняются при переходе от одной итерации к другой.

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

Здесь требовалось получить список, состоящий из копий одного и того же слова чётной длины, в котором по очереди будут подняты в регистре пары букв. Кстати, попробуйте эту задачу прогнать между делом по всем 5 этапам нашего алгоритма размышлений.

Как видим, здесь в ключевой команде - набор уже из 4 объектов. Для первой итерации - 0,0,2,2, для второй - 2,2,4,4, и т. д. В рамках каждой группы необходимо уследить внутреннюю связь между объектами. Здесь она довольно проста: мы имеем два одинаковых числа, и ещё два одинаковых, которые всегда больше первых ровно на 2. Приглядитесь, и увидите эту связь. Зачем нам это нужно? Напомню, у нас цель - написать цикл. Пока что итерации отличаются друг от друга, хоть и несильно. Тем не менее, наша задача - превратить их в универсальный кусок кода, который можно будет разместить в теле грядущего цикла. Внутренняя связь между объектами в группе позволит избежать, например, использования множественных переменных. Каждая группа теперь - n, n, n+2, n+2. Самую первую замену из этих четырёх назовём главной переменной. Если бы бы не заморачивались об этой связи, то набор был бы более напряжным - a, b, c, d. Поверьте, вы сами себе скажете "спасибо", когда уменьшите количество переменных в коде и увеличите число логических взаимосвязей между его частями.

  • этап [4] Уловить закономерность изменения главной переменной при переходе от предыдущей итерации к следующей.

    Для этого часто нужно понять смысл того объектам в алгоритме, который представлен этой главной переменной. В алгоритме со строкой "resident" имеем ряд 0,2,4,6. По смыслу - это индекс первой буквы, "поднятой по регистру". По внешнему виду - арифметическая прогрессия (сразу мысль о функции range()) с шагом 2, которая всегда начинается с 0 и кончается числом, на 2 меньшим, чем длина слова (длина слова "resident" равна 8).

    Возвращаясь к нашим миллионерам из шоу-бизнеса, видим иную картину: здесь по смыслу объект, представленный главной переменной, играет роль индекса каждого элемента входного списка.

Придётся перебрать все индексы списка. Какой командой это сделать - думаю, подсказки не нужно.

  • этап [5] Завершение. Просто приписываем заголовок цикла по всем канонам к уже понятной универсальной итерации.

Заключение

Программирование очень похоже на работу классического крутого детектива из голливудских сериалов. Постоянно нужно улавливать связь между вещями, которые на первый взгляд абсолютно разрознены. Жду критики моих философствований от гуру программирования внизу в комментариях. Ну а если вы просто человек, который пока далёк от программирования, но жаждет научиться, общаясь по-человечески, а не заумными научными терминами, то дайте о себе знать.

Теги:
Хабы:
Всего голосов 25: ↑8 и ↓17-8
Комментарии79

Публикации

Истории

Работа

Data Scientist
70 вакансий
Python разработчик
110 вакансий

Ближайшие события