Курс по Python: https://stepik.org/course/100707
На этом занятии мы поговорим о функциях all() и any(). Первым делом
посмотрим, что они делают и зачем нужны? Начнем с функции all() и очень
простого примера. Предположим, что есть список булевых значений:
a = [True, True, True, True]
И мы хотим
узнать, принимают ли все они значение True? Для этого, как
раз и используется функция all(), которая на вход принимает
итерируемый объект и все его значения приводит к булевым величинам:
Если все
значения равны True, то на выходе получаем True. Если же, хотя
бы одно значение принимает False, то на выходе будет False:
all([True, True, False, True])
Но, как вы
понимаете, значения в списках могут быть любыми, например, такими:
a = [0, 1, 2.5, "", "python", [], [1, 2], {}]
И к нему тоже
можно применить функцию all():
Как она работает?
Помните, когда мы говорили о типе bool, то говорили,
что любое значение можно привести к этому типу? В частности:
даст False, так как 0
воспринимается, как пустое значение. По тем же причинам False получается и для:
bool("")
bool([])
bool({})
А вот все, что
не пустое, превращается в True:
Именно так
вначале происходит преобразование списка, а затем, применяется функция all(). И, так как
список содержит значения False, то и результат равен False.
Работу этой
функции можно повторить с помощью обычных булевых операций. Если вначале
объявить некую переменную со значением True:
all_res = True
for x in a:
all_res = all_res and bool(x)
print(all_res)
А, затем, в
цикле для каждого элемента выполнять оператор and, то эта
переменная сохранит начальное значение True только в том
случае, если не встретится ни один False. Я вам показал
этот способ, чтобы вы знали как действовать в других языках программирования,
где нет уже готовой функции all(). В Python, конечно,
следует использовать эту функцию – это и удобнее и быстрее.
Вторая функция any() работает
похожим образом, но возвращает True, если встретилось хотя бы одно такое
значение. Например, для списка:
мы увидим
значение True. А вот если
передать список со всеми False:
any([False, False, False, False])
то только в этом
случае она вернет False.
Повторим также
работу этой функции через булевы операции. Начальное значение переменной здесь
нужно присвоить False:
any_res = False
for x in a:
any_res = any_res or bool(x)
print(any_res)
А, затем, в
цикле с помощью оператора or (или) корректировать это значение
текущей булевой величиной. Если встретится хотя бы один True, то оператор or вернет True и оно
сохранится в переменной any_res, что бы в
дальнейшем не появлялось.
Вот принцип
работы этих двух функций. Ну и, наверное, самый главный вопрос, где это имеет
смысл применять? Давайте представим, что мы делаем игру «Крестики-нолики» и
хотели бы на каждом шаге определять, есть ли выигрышная позиция, например, у
крестиков? Для простоты сделаем это следующим образом. Все поле из девяти
клеток я представлю одномерным списком (сейчас вы узнаете, зачем):
P = ['x', 'x', 'o', 'o', 'x', 'o', 'x', 'x', 'x']
Тогда, чтобы
проверить выигрышные ситуации по строкам, можно воспользоваться функцией all(), следующим
образом:
row_1 = all(map(lambda x: x == 'x', P[:3]))
row_2 = all(map(lambda x: x == 'x', P[3:6]))
row_3 = all(map(lambda x: x == 'x', P[6:]))
print(row_1, row_2, row_3)
Смотрите, мы
здесь используем вложенный вызов функции map(), чтобы
правильно преобразовать крестики в True, а нолики – в False, иначе бы все
преобразовалось в True. Далее, срез для каждой строки на выходе функции map()
обрабатывается функцией all() и получаем результат: True – есть
выигрышная комбинация; False – нет выигрышной
комбинации.
Кстати,
внимательный и грамотный зритель здесь сразу должен возмутиться из-за
дублирования кода – три раза записана одна и та же анонимная функция.
Действительно, это лучше поправить и использовать свою собственную:
def true_x(a):
return a == 'x'
И, затем,
указать ее в функции map():
row_1 = all(map(true_x, P[:3]))
row_2 = all(map(true_x, P[3:6]))
row_3 = all(map(true_x, P[6:]))
Теперь известный
принцип DRY – сохраняется. По
аналогии можно сделать проверку выигрыша по столбцам:
col_1 = all(map(true_x, P[::3]))
col_2 = all(map(true_x, P[1::3]))
col_3 = all(map(true_x, P[2::3]))
print(col_1, col_2, col_3)
А по диагоналям
сделайте самостоятельно – это несложно.
Для второй
функции я приведу такой короткий пример. Предположим, мы делаем игру «Сапер» и
игровое поле также представлено в виде одномерного списка длиной NxN элементов:
Далее, если в
этом списке появляется хотя бы одна мина (отметим ее звездочкой):
то игрок
проигрывает. Чтобы узнать, наступил ли игрок на мину, удобно воспользоваться
функцией any():
loss = any(map(lambda x: x == '*', P))
print(loss)
После запуска
программы увидим значение True, то есть, игрок проиграл. А если мину
поставить в комментарий и снова запустить, то увидим значение False.
Вот два простых
примера, где удобно применять эти две функции any() и all().
Курс по Python: https://stepik.org/course/100707