Pythonの組み込み関数all(), any()の使い方
Pythonでリストやタプルなどのイテラブルオブジェクトの要素がすべてTrue
(真)か、いずれか一つでもTrue
か、あるいは、すべてFalse
(偽)かを判定するには組み込み関数all()
, any()
を使う。
- 組み込み関数 - all() — Python 3.7.1rc2 ドキュメント
- すべての要素が
True
であればTrue
を返す
- すべての要素が
- 組み込み関数 - any() — Python 3.7.1rc2 ドキュメント
- いずれかの要素が
True
であればTrue
を返す
- いずれかの要素が
ここでは、all()
およびany()
の使い方として、以下の内容について説明する。
- Pythonにおける真偽値の判定
- すべての要素が
True
か判定:all()
- いずれかの要素が
True
か判定:any()
- すべての要素が
False
か判定:not any()
- 条件で判定: リスト内包表記、ジェネレータ式
- リスト内包表記、ジェネレータ式に対する
all()
,any()
- ジェネレータ式のメリット(処理速度比較)
- リスト内包表記、ジェネレータ式に対する
- 条件を満たす要素の数をカウント
Pythonにおける真偽値の判定
Pythonには真偽値bool
型のTrue
とFalse
があるが、if文などの条件での判定では、数値や文字列などの他の型もTrue
かFalse
かいずれかに判定される。
以下のオブジェクトはFalse
と判定される。
- 偽であると定義されている定数:
None
とFalse
- 数値型におけるゼロ:
0
,0.0
,0j
(複素数),Decimal(0)
,Fraction(0, 1)
- 空のシーケンスまたはコレクション:
''
,()
,[]
,{}
,set()
,range(0)
その他のオブジェクトはすべてTrue
と判定される。
詳細は以下の記事を参照。
以降で説明するall()
, any()
においてもこのルールに従って真偽が判定される。
すべての要素がTrueか判定: all()
all()
は引数に指定したイテラブルオブジェクトの要素がすべてTrue
と判定されるとTrue
を返す。一つでもFalse
があれば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
all()
は以下のコードと等価。
def all(iterable):
for element in iterable:
if not element:
return False
return True
したがって、空のイテラブルオブジェクトにはTrue
を返す。
print(all([]))
# True
上述のように、bool
型のTrue
, False
だけでなく、その他の型も判定して結果が返される。
print(all([100, [0, 1, 2], 'abc']))
# True
print(all([100, [0, 1, 2], 'abc', {}]))
# False
いずれかの要素がTrueか判定: any()
any()
は引数に指定したイテラブルオブジェクトの要素のいずれかがTrue
と判定されるとTrue
を返す。すべてFalse
であれば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
any()
は以下のコードと等価。
def any(iterable):
for element in iterable:
if element:
return True
return False
したがって、空のイテラブルオブジェクトにはFalse
を返す。
print(any([]))
# False
上述のように、bool
型のTrue
, False
だけでなく、その他の型も判定して結果が返される。
print(any([False, None, 0, 0.0, 0 + 0j, '', [], {}, ()]))
# False
print(any([False, None, 0, 0.0, 0 + 0j, '', [], {}, (), 1]))
# True
すべての要素がFalseか判定: not any()
any()
はひとつでもTrue
があるとTrue
を返し、すべての要素がFalse
のときのみFalse
を返す。
したがって、not
でany()
の否定をとることで、すべての要素がFalse
のときのみTrue
とすることができる。
print(not any([False, False, False]))
# True
print(not any([True, False, False]))
# False
条件で判定: リスト内包表記、ジェネレータ式
リスト内包表記、ジェネレータ式に対するall(), any()
これまでの例はイテラブルオブジェクトの要素をそのままTrue
かFalse
か判定していたが、内包表記を使うと、任意の条件に対してall()
やany()
を適用できる。
すべての要素が条件を満たすかどうかなどの判定が可能。
あるイテラブルオブジェクトの各要素に対する条件判定の結果は、リスト内包表記を使って以下のように取得できる。
l = [0, 1, 2, 3, 4]
print([i > 2 for i in l])
# [False, False, False, True, True]
リスト内包表記の詳細は以下の記事を参照。
- 関連記事: Pythonリスト内包表記の使い方
この結果を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'>
ジェネレータ式を唯一の引数として関数を呼び出す場合、()
を省略可能。
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
である場合、ジェネレータ式のほうが遥かに速くなる。
%%timeit
all([i < 0 for i in l])
# 4.15 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
all(i < 0 for i in l)
# 469 ns ± 6.12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
すべての要素がTrue
(all()
の結果がTrue
)だと最後の要素まで処理する必要があるのでジェネレータ式でも速くならない。例の場合はむしろ遅くなっている。
%%timeit
all([i >= 0 for i in l])
# 4.5 ms ± 57.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
all(i >= 0 for i in l)
# 5.49 ms ± 255 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
このように、ジェネレータ式はどこでFalse
と判定されるかによって処理時間が異なる。中央でFalse
だと判定される場合は半分くらいの処理時間になる。
%%timeit
all(i < 50000 for i in l)
# 2.73 ms ± 37.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
any()
でも同様。any()
の場合、True
が一つでもあると結果がTrue
だと確定するため、ジェネレータ式ではTrue
が出てきた時点で処理が終了する。
%%timeit
any([i >= 0 for i in l])
# 4.2 ms ± 183 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
any(i >= 0 for i in l)
# 468 ns ± 4.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%%timeit
any([i < 0 for i in l])
# 4.56 ms ± 180 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
any(i < 0 for i in l)
# 5.33 ms ± 45.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
any(i > 50000 for i in l)
# 2.78 ms ± 120 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
条件を満たす要素の数をカウント
True
は1
、False
は0
として処理されるので、sum()
を使うとTrue
の数、すなわち、条件を満たす要素の数を取得できる。
print(sum(i > 2 for i in l))
# 2
False
の数をカウントしたい場合はnot
を使えばOK。
print(sum(not (i > 2) for i in l))
# 3