Как записать цикл в одну строку python
Перейти к содержимому

Как записать цикл в одну строку python

  • автор:

5++ способов в одну строку на Python решить первую задачу Проекта Эйлера

Однажды меня посетила мысль, а что если попробовать решить первую задачу Проекта Эйлера всевозможными способами, но с условием, что решение должно быть в одну строку. В итоге получилось более пяти однострочных решений с применением Filter, Map, Reduce, Generator Expression и т.д. В этой статье я покажу то, к чему я пришёл.

Это моя первая статья. Стоит отнестись к ней настороженно. Уникальные решения будут оформлены в отдельные пункты. Менее уникальные — в подпункты.

Условие задачи

Если выписать все натуральные числа меньше 10, кратные 3 или 5, то получим 3, 5, 6 и 9. Сумма этих чисел равна 23.

Найдите сумму всех чисел меньше 1000, кратных 3 или 5.

00 — Базовое решение

Прежде чем перейти непосредственно к однострочным решениям, разумно было бы упомянуть сначала стандартное, классическое решение:

result = 0 for i in range(1, 1000): if i%3 == 0 or i%5 == 0: result += i print(result) # => 233168

Перебираем последовательность чисел от 1 до 999. Если перебираемое число делится на 3 или на 5 без остатка от деления, то прибавляем каждое такое число в заранее объявленную переменную result .

01 — Generator Expression. Выражение-генератор

print(sum(i for i in range(1, 1000) if i%3 == 0 or i%5 == 0)) # => 233168

Числа из последовательности от 1 до 999, делящиеся на 3 или на 5 без остатка от деления, собираются в генератор. Затем функция sum() складывает содержимое генератора.

01.a — List Comprehension. Выражение на основе списка
print(sum([i for i in range(1, 1000) if i%3 == 0 or i%5 == 0])) # => 233168

В отличии от предыдущего, здесь выражение дополнительно помещается в список. Стоило упомянуть этот вариант, так как он довольно часто встречается в различных статьях.

01.b — Set Comprehension. Выражение на основе множества
print(sum()) # => 233168

Тоже, что и в предыдущем, но вместо списка здесь множество.

02 — Filter

print(sum(filter(lambda i: i%3 == 0 or i%5 == 0, range(1, 1000)))) # => 233168

Функция filter схожа по принципу работы с выражением-генератором. Функция лямбда применяется к каждому элементу последовательности чисел от 1 до 999. Все числа последовательности, делящиеся на 3 или на 5 без остатка от деления, возвращаются, затем суммируются функцией sum() .

03 — Map

print(sum(map(lambda i: i if i%3 == 0 or i%5 == 0 else 0, range(1, 1000)))) # => 233168

Перебираемые числа последовательности от 1 до 999, делящиеся на 3 или 5 без остатка от деления, остаются без изменений, все остальные числа заменяются на ноль. Полученная последовательность суммируется функцией sum() .

04 — Reduce

from functools import reduce print(reduce(lambda x, y: x+y if y%3 == 0 or y%5 == 0 else x, range(1, 1000), 0)) # => 233168

Из всей подборки, этот вариант «очень не очень». Как по степени реализации, так и по времени выполнения(но об этом попозже).
Если в reduce указан инициализатор(в нашем случае ноль), то он становится накопителем. К нему по очереди прибавляются только те числа из последовательности от 1 до 999, которые делятся на 3 или на 5 без остатка от деления. Если из функции reduce убрать инициализатор ноль, то инициализатором станет крайний левый элемент последовательности.

05 — Однострочное решение на основе множества

print(sum(set(range(3, 1000, 3)) | set(range(5, 1000, 5)))) # => 233168

Самое элегантное решение, как по красоте написания, так и по времени выполнения.
Последовательность чисел от 1 до 999, кратную трём, помещаем во множество и объединяем со множеством, содержащим в себе последовательность чисел от 1 до 999, кратную пяти. Содержимое, полученного множества суммируем функцией sum() .

05.a — Ещё одно однострочное решение на основе множества
print(sum( <*range(3, 1000, 3)>| <*range(5, 1000, 5)>)) # => 233168

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

05.b — И ещё одно однострочное решение на основе множества
print(sum(set(range(3, 1000, 3)).union(range(5, 1000, 5)))) # => 233168

Создаём множество, с последовательностью чисел от 1 до 999, кратную трём и присоединяем к нему последовательность чисел от 1 до 999, кратную пяти. Затем функцией sum() суммируем.

05.c И последнее однострочное решение на основе множества
print(sum(set([*range(3, 1000, 3)] + [*range(5, 1000, 5)]))) # => 233168

По аналогии с предыдущими. Распаковываем последовательности чисел в списки. Складываем списки. Оборачиваем во множество. Затем суммируем функцией sum() .

Смотрим на скорость выполнения каждого однострочного решения

Если проверить скорость выполнения каждого однострочного решения в командной строке, при помощи timeit, получим следующие значения в микросекундах:

sum(i for i in range(1, 1000) if i%3 == 0 or i%5 == 0) # 203 usec sum([i for i in range(1, 1000) if i%3 == 0 or i%5 == 0]) # 181 usec sum() # 189 usec sum(filter(lambda i: i%3 == 0 or i%5 == 0, range(1, 1000))) # 306 usec sum(map(lambda i: i if i%3 == 0 or i%5 == 0 else 0, range(1, 1000))) # 313 usec reduce(lambda x, y: x+y if y%3 == 0 or y%5 == 0 else x, range(1, 1000), 0)# 324 usec sum(set(range(3, 1000, 3)) | set(range(5, 1000, 5))) # 47 usec sum( <*range(3, 1000, 3)>| <*range(5, 1000, 5)>) # 47 usec sum(set(range(3, 1000, 3)).union(range(5, 1000, 5))) # 41 usec sum(set([*range(3, 1000, 3)] + [*range(5, 1000, 5)])) # 43 usec

Методика расчёта: python -m timeit «выражение»

Быстрее всего справились с задачей последние четыре варианта.

Заключение

Всего получилось 5 уникальных + 5 не уникальных решений. Благодаря этой задаче у меня появилось более устойчивое понимание работы функций Filter, Map, Reduce. И если раньше я недоумевал, почему функцию Reduce убрали из основного модуля, то теперь я не сомневаюсь в правильности этого решения.

В статье я старался отойти от популярного шаблона повествования «точность на грани бесполезности». Где предложения набиты под завязку «тяжёлыми» терминами, а из знакомого там только союзы и предлоги. Не уверен, что у меня получилось.

Как вывести цикл в одну строку питон

1) Функция print() имеет параметр end , указывающий какой символ или какую строку выводить после вывода каждого значения (по дефолту переходом на новую строку, т.е. строкой ‘\n’ ). Укажите необходимый разделитель (например пробельной строкой ‘ ‘ ):

for x in range(0, 5): print(x, end=' ') # => 0 1 2 3 4 

2) Перед выводом данные можно агрегировать в массив, который затем методом join() соединяем и выводим одной строкой:

array = [] for x in range(0, 5): array.append(str(x)) # => [0, 1, 2, 3, 4] print(' '.join(array)) # => 0 1 2 3 4 

При этом все элементы должны быть строковыми объектами, поэтому в цикле мы приводили числа к строкам str(x) .

Как сделать цикл for и условие if in в одну строку?

вопрос следующего типа.
цикл for с последующим условием if in будет использоваться более 1000 раз.
Можно ли как то сократить в 1 строку?

  • Вопрос задан 02 апр.
  • 487 просмотров

Комментировать
Решения вопроса 1

Vindicar

цикл for с последующим условием if in будет использоваться более 1000 раз.
Можно ли как то сократить в 1 строку?

Можешь пояснить, какая вообще связь между длиной кода и числом использований?

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

Сейчас выглядит как будто ты пишешь этакого чат-бота для терминала. Если я прав, то длинная цепочка из if-elif-elif тут не подойдёт.

Но если прямо невтерпёж, то

if any(word in text for word in ["привет", "хай"]):

Ответ написан 02 апр.
Нравится 2 5 комментариев

RoMoN777

RoMoN @RoMoN777 Автор вопроса
от души эта строка то что мне нужно.
да делаю чат бота телеграмм.

Vindicar

RoMoN, лучше используй существующие средства для выбора команды. У большинства библиотек что-то да есть.

А как в таком однострочнике расположить break ?

Vindicar

hulitolku, никак, да и не надо. Как ты это себе вообще представляешь?

Vindicar, Ну допустим список [«привет», «хай»] состоит из десятки тысяч элементов, и чтобы не тратить время, пробегая по всему списку, если например слово найдется в самом начале, то брейк будет прерывать цикл.

Ответы на вопрос 1

RimMirK

Вроде человек. Вроде учусь. Вроде пайтону
походу, никак

C:\Users\User>py Python 3.10.8 (tags/v3.10.8:aaaf517, Oct 11 2022, 16:50:30) [MSC v.1933 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> text = '123' >>> print('hello') if command in text for command in ["привет", "хай"] File "", line 1 print('hello') if command in text for command in ["привет", "хай"] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: expected 'else' after 'if' expression >>> print('hello') if command in text else pass for command in ["привет", "хай"] File "", line 1 print('hello') if command in text else pass for command in ["привет", "хай"] ^^^^ SyntaxError: invalid syntax >>> print('hello') if command in text else . for command in ["привет", "хай"] File "", line 1 print('hello') if command in text else . for command in ["привет", "хай"] ^^^ SyntaxError: invalid syntax >>> print('hello') if command in text else print('',end='') for command in ["привет", "хай"] File "", line 1 print('hello') if command in text else print('',end='') for command in ["привет", "хай"] ^^^ SyntaxError: invalid syntax >>> command print('hello') if command in text else print('',end='') for command in ["привет", "хай"] File "", line 1 command print('hello') if command in text else print('',end='') for command in ["привет", "хай"] ^^^^^ SyntaxError: invalid syntax >>> print('hello') if command in text else print('',end='') command for command in ["привет", "хай"] File "", line 1 print('hello') if command in text else print('',end='') command for command in ["привет", "хай"] ^^^^^^^ SyntaxError: invalid syntax >>> print('hello') if command in text else print('',end='') for command in ["привет", "хай"] File "", line 1 print('hello') if command in text else print('',end='') for command in ["привет", "хай"] ^^^ SyntaxError: invalid syntax

Цикл for в одну строку

Как и большинство программистов, вы знаете, что после создания массива, вам нужно написать цикл для его обработки. С этим нет никаких проблем, но иногда нам не нужно использовать несколько строк для написания полного цикла for для одной простой задачи. К частью, Python это понимает и предоставляет замечательный инструмент для использования в таких ситуациях. Этот инструмент называется генератор списка (list comprehensions, списковое включение).

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Что это за зверь?

Списковое включение (List comprehensions) – это списки, которые генерируются с циклом for внутри. Они очень распространены в Python и выглядят примерно следующим образом:

[ thing for thing in list_of_things ]

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

my_list = [ 21 , 2 , 93 ]

Теперь создадим функцию. Назовем ее list_doubler , так как это именно то, что она делает, и она будет принимать аргумент, который является списком, который мы будем удваивать.

def list_doubler ( lst ) :
for num in lst :
doubled . append ( num * 2 )
return doubled

Вызов этой функции даст нам новый список с удвоенными элементами.

my_doubled_list = list_doubler ( lst )

my_doubled_list теперь содержит значения 42 , 4 и 186 . Эта функция простая и делает то, что нам нужно простым способом, но это пять строк, учитывая определяющую строку. Также есть переменная, с которой мы ничего не делаем, кроме как добавляем и в конце возвращаем её.

Единственная часть функции, которая по-настоящему работает – это цикл for. Цикл for тоже мало что делает, просто умножает число на 2. Это идеальный кандидат для превращения в списковое включение.

Создание спискового включения

Давайте сохраним его как функцию, которую мы будем вызывать. Нам нужно только упростить тело функции. Так как списковое включение создает списки, а списки могут быть назначены к переменным, примем это во внимание и расположим списковое включение справа от doubled и продолжим.

doubled = [ thing for thing in list_of_things ]

Хорошо, теперь нам нужно заполнить правую сторону. Как и с нормальным циклом for, а правая часть списка выглядит именно так, нам нужно назвать элементы в нашем цикле. Сначала, назовем каждый объект, и мы также будем использовать переменную списка, которая будет передана.

doubled = [ thing for num in lst ]

Это не может работать в полной мере, так как элемент не является… элементом. В нашей изначальной функции мы выполнили num * 2 , так что давайте сделаем это еще раз.

doubled = [ num * 2 for num in lst ]

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

def list_doubler ( lst ) :
doubled = [ num * 2 for num in lst ]
return doubled

Запускаем нашу новую функцию.

my_doubled_list = list_doubler ( [ 12 , 4 , 202 ] )

И да, my_doubled_list содержит ожидаемые значения 24 , 8 и 404 . Отлично, все работает! Но так как мы создаем и моментально возвращаем переменную, давайте просто применим списковое включение напрямую.

def list_doubler ( lst ) :
return [ num * 2 for num in lst ]

Хорошо, отлично, но зачем мне это нужно?

Списковые включения (генератор списка, list comprehensions) отлично подходят для случаев, когда нам нужно сохранить немного места в коде. Они также удобны в случаях, когда вам просто нужно быстро обработать списки, чтобы сэкономить время над рутинной работой с этим списком.

Они также очень полезны, если вы хотите больше узнать о функциональном программировании, но эту тему мы обсудим в будущем.

Применяем условие if в список

Давайте сделаем новую функцию, которая будет давать только длинные слова из списка. Скажем, каждое слово, которое состоит более чем из 5 букв, будет считаться длинным. Для начала пропишем их вручную.

def long_words ( lst ) :
for word in lst :
if len ( word ) > 5 :
words . append ( word )
return words

Мы создали переменную для хранения наших слов, применяем цикл над всеми словами в нашем списке, и проверяем длинну каждого слова. Если оно длиннее 5 букв, мы вносим слово в список, и затем, наконец, мы отсылаем список назад. Давайте попробуем.

long_words([‘blog’, ‘Treehouse’, ‘Python’, ‘hi’]) возвращает [‘Treehouse’, ‘Python’] . Это как раз то, чего мы и ожидали.

Хорошо, давайте перепишем это в списковое включение. Для начала, построим то, что мы и так знаем.

def long_words ( lst ) :
return [ word for word in lst ]

Это возвращает нам все слова, не только те, которые длиннее 5 букв. Мы вносим условный оператор в конец цикла for.

def long_words ( lst ) :
return [ word for word in lst if len ( word ) > 5 ]

Итак, мы использовали всё то же условие if, но поместили его в конец спискового включения. Оно использует то же наименование переменной, которое мы используем для элементов в списке.

Хорошо, давайте опробуем эту версию long_words([‘list’, ‘comprehension’, ‘Treehouse’, ‘Ken’]) возвращает [‘comprehension’, ‘Treehouse’] .

Примеры

1. Возводим в квадрат все числа от 1 до 9. Применяем функцию range.

[ x * * 2 for x in range ( 10 ) ]
[ 0 , 1 , 4 , 9 , 16 , 25 , 36 , 49 , 64 , 81 ]

2. Все цифры которые делятся на 5 без остатка, в диапазоне от 0 до 100.

[ x for x in range ( 100 ) if x % 5 == 0 ]
[ 0 , 5 , 10 , 15 , 20 , 25 , 30 , 35 , 40 , 45 , 50 , 55 , 60 , 65 , 70 , 75 , 80 , 85 , 90 , 95 ]

3. Все цифры которые делятся на 3 и 6 без остатка, в диапазоне от 0 до 50.

[ x for x in range ( 50 ) if x % 3 == 0 and x % 6 != 0 ]
[ 3 , 9 , 15 , 21 , 27 , 33 , 39 , 45 ]

4. Первая буква из каждого слова предложения.

phrase = «Тестовое сообщение из мира Python для сообщества.»
print ( [ w [ 0 ] for w in phrase . split ( ) ] )
[ ‘Т’ , ‘с’ , ‘и’ , ‘м’ , ‘P’ , ‘д’ , ‘с’ ]

5. Заменяем букву А в каждом слове на # .

phrase = «АБАЖУР, АБАЗИНСКИЙ, АБАЗИНЫ, АББАТ, АББАТИСА, АББАТСТВО»
print ( » . join ( [ letter if letter != ‘А’ else ‘#’ for letter in phrase ] ) )
#Б#ЖУР, #Б#ЗИНСКИЙ, #Б#ЗИНЫ, #ББ#Т, #ББ#ТИС#, #ББ#ТСТВО

Итоги

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

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

Если это только распалило ваш аппетит, посмотрим, сможете ли вы разобраться со словарными включениями самостоятельно. Они используют конструкторы dict, , но они довольно похожи. Вы также можете проработать установочные включения. Также ознакомьтесь с функциональным программированием в Python, если считаете себя готовым.

Больше примеров

  • https://www.python.org/dev/peps/pep-0289/
  • https://legacy.python.org/dev/peps/pep-0274/

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *