Pythonの組み込み関数all(), any()の使い方
Pythonでリストやタプルなどのイテラブルオブジェクトの要素がすべて真か、いずれか一つでも真か、すべて偽かを判定するには組み込み関数all()およびany()を使う。
- 組み込み関数 - all() — Python 3.13.3 ドキュメント
- すべての要素が真なら
Trueを返す
- すべての要素が真なら
- 組み込み関数 - any() — Python 3.13.3 ドキュメント
- いずれかの要素が真なら
Trueを返す
- いずれかの要素が真なら
Pythonにおける真偽値の判定
Pythonには真偽値bool型のTrueとFalseがあるが、if文の条件などにおいては、数値や文字列など他の型も真か偽のいずれかに判定される。
以下のオブジェクトは偽と判定される。
- 偽であると定義されている定数:
NoneとFalse- 数値型におけるゼロ:
0,0.0,0j,Decimal(0),Fraction(0, 1)- 空のシーケンスまたはコレクション:
'',(),[],{},set(),range(0)組み込み型 - 真理値判定 — Python 3.13.3 ドキュメント
その他のオブジェクトはすべて真と判定される。
詳細は以下の記事を参照。
以降で説明するall()とany()においてもこのルールに従って真偽が判定される。
すべての要素が真(True)か判定: all()
all()は引数に指定したイテラブルオブジェクトの要素がすべて真ならTrueを返す。一つでも偽ならFalse。
print(all([True, True, True]))
# True
print(all([True, False, True]))
# False
リストに限らず、タプルや集合setなど他のイテラブルオブジェクトも引数に指定できる。
print(all((True, True, True)))
# True
print(all({True, True, True}))
# True
上述のように、bool型のTrueやFalseだけでなく、他の型のオブジェクトも判定して結果が返される。空文字列や0は偽、それ以外の文字列や数値は真と判定される。
print(all(['aaa', 'bbb', 'ccc']))
# True
print(all(['aaa', 'bbb', 'ccc', '']))
# False
print(all([1, 2, 3]))
# True
print(all([0, 1, 2, 3]))
# False
all()は以下のコードと等価。
def all(iterable):
for element in iterable:
if not element:
return False
return True
したがって、空のイテラブルオブジェクトにはTrueを返す。
print(all([]))
# True
いずれかの要素が真(True)か判定: any()
any()は引数に指定したイテラブルオブジェクトの要素のいずれかが真ならTrueを返す。すべて偽ならFalse。
print(any([True, False, False]))
# True
print(any([False, False, False]))
# False
リストに限らず、タプルや集合setなど他のイテラブルオブジェクトも引数に指定できる。
print(any((True, False, False)))
# True
print(any({True, False, False}))
# True
上述のように、bool型のTrueやFalseだけでなく、他の型のオブジェクトも判定して結果が返される。
print(any(['aaa', 'bbb', 'ccc', '']))
# True
print(any(['', '', '', '']))
# False
print(any([0, 1, 2, 3]))
# True
print(any([0, 0, 0, 0]))
# False
any()は以下のコードと等価。
def any(iterable):
for element in iterable:
if element:
return True
return False
したがって、空のイテラブルオブジェクトにはFalseを返す。
print(any([]))
# False
すべての要素が偽(False)か判定: not any()
any()は要素が一つでも真ならTrueを返し、すべての要素が偽であるときのみFalseを返す。したがって、notでany()の否定をとることで、すべての要素が偽であるときにTrueと判定できる。
print(not any([False, False, False]))
# True
print(not any([True, False, False]))
# False
条件で判定: リスト内包表記、ジェネレータ式
リスト内包表記、ジェネレータ式に対するall(), any()
これまでの例はイテラブルオブジェクトの要素をそのまま真か偽か判定していたが、内包表記を使うと、任意の条件に対してall()やany()を適用できる。
すべての要素が条件を満たすかどうかなどの判定が可能。
あるイテラブルオブジェクトの各要素に対する条件判定の結果は、リスト内包表記を使って以下のように取得できる。
- 関連記事: Pythonリスト内包表記の使い方
l = [0, 1, 2, 3, 4]
print([i > 2 for i in l])
# [False, False, False, True, True]
この結果をall(), any()の引数に指定すると、各要素がすべて条件を満たすか、一つでも条件を満たすかといった判定ができる。
print(all([i > 2 for i in l]))
# False
print(any([i > 2 for i in l]))
# True
ここで、リスト内包表記の[]を()に変えるとジェネレータ式となり、リストではなくジェネレータを返す。
print(type([i > 2 for i in l]))
# <class 'list'>
print(type((i > 2 for i in l)))
# <class 'generator'>
ジェネレータ式を唯一の引数として関数を呼び出す場合は()を省略可能なので、以下のようにall(), any()の引数に指定できる。
print(all(i > 2 for i in l))
# False
print(any(i > 2 for i in l))
# True
ジェネレータ式のメリット(処理速度比較)
ジェネレータはリストと異なり逐次処理されるので、処理時間やメモリ使用量を抑えられるというメリットがある。
以下のような要素数100000個の連番のリストを例とする。
l = list(range(100000))
print(l[:5])
# [0, 1, 2, 3, 4]
print(l[-5:])
# [99995, 99996, 99997, 99998, 99999]
print(len(l))
# 100000
このリストに対するリスト内包表記とジェネレータ式のall(), any()の処理時間を比較する。以下の例はJupyter Notebookのマジックコマンド%%timeitを利用しており、Pythonスクリプトとして実行しても計測されないので注意。
all()の場合、Falseが一つでもあると結果がFalseだと確定する。
リスト内包表記ではすべての要素に対して式(下の例の場合はi < 0)を評価してリストを生成してall()やany()に渡すが、ジェネレータ式では先頭の要素から順次処理される。Falseの要素がある時点でall()の結果が確定するため、例えば先頭の要素がFalseである場合、ジェネレータ式のほうが遥かに速くなる。
ms(ミリ秒)、μs(マイクロ秒)、ns(ナノ秒)と単位が混在しているので注意。
%%timeit
all([i < 0 for i in l])
# 963 μs ± 22.8 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
all(i < 0 for i in l)
# 132 ns ± 4.21 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
すべての要素がTrue(all()の結果がTrue)だと最後の要素まで処理する必要があるのでジェネレータ式でも速くならない。例の場合はむしろ遅くなっている。
%%timeit
all([i >= 0 for i in l])
# 1.11 ms ± 18.2 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
all(i >= 0 for i in l)
# 1.75 ms ± 2.53 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
このように、ジェネレータ式はどこでFalseと判定されるかによって処理時間が異なる。中央でFalseだと判定される場合は半分くらいの処理時間になる。
%%timeit
all(i < 50000 for i in l)
# 882 μs ± 2.92 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
any()でも同様。any()の場合、Trueが一つでもあると結果がTrueだと確定するため、ジェネレータ式ではTrueが出てきた時点で処理が終了する。
%%timeit
any([i >= 0 for i in l])
# 902 μs ± 5.31 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
any(i >= 0 for i in l)
# 123 ns ± 0.0354 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%%timeit
any([i < 0 for i in l])
# 1.1 ms ± 2.88 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
any(i < 0 for i in l)
# 1.75 ms ± 6.04 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%%timeit
any(i > 50000 for i in l)
# 897 μs ± 6.9 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
条件を満たす要素の数をカウント
Trueは1、Falseは0として処理されるので、sum()を使うとTrueの数、すなわち、条件を満たす要素の数を取得できる。
print(sum(i > 2 for i in l))
# 2
Falseの数をカウントしたい場合はnotを使えばよい。
print(sum(not (i > 2) for i in l))
# 3