[Python入門]リストと繰り返し処理:Python入門(3/3 ページ)
リストはfor文を使用した繰り返し処理とよく組み合わせて使われる。そこで便利に使える関数や「イテレータ」という概念などを取り上げる。
map関数
map関数は、リストの各要素に対して、一定の処理を加えて得られた結果を要素とするイテレータを戻り値とする。
map関数
map(function, iterable, ……)
パラメーター | 説明 |
---|---|
function | iterableの要素を引数に受け取り何らかの結果を返す関数。iterableを複数指定したときには、functionはそれらの数だけ引数を持つ必要がある |
iterable | functionで処理をしたい反復可能オブジェクト |
map関数のパラメーター |
例えば、整数を要素とするリストがあり、その値を二乗した値を要素とするリストを作るコードは次のようになる。map関数の戻り値はイテレータなので、list関数に渡してリストを作成している点にも注意しよう。
intlist = list(range(5))
result = map(lambda x: x * x, intlist)
print(intlist)
print(list(result)) # map関数の戻り値(イテレータ)からリストを作成
ただし、これはリスト内包表記を使って次のようにも表現できる。
result = [x * x for x in intlist]
print(result)
以下に実行結果を示す。
どちらを使うかは好みの問題ともいえるが、速度面では内包表記の方が有利だ。
filter関数
map関数と同様にリストに何らかの処理を適用して、その結果を基に新たなイテレータを作成する関数としてはfilter関数もある。これについては既に第15回「ローカル関数とラムダ式」の「ラムダ式」の例で触れたが、簡単に説明だけしておこう。
filter関数は、関数とリスト(反復可能オブジェクト)を引数に取り、その関数にリストの各要素を渡して、その結果が真となるものだけを要素とするイテレータを戻り値とする。以下に例を示す。
intlist = list(range(10)) # [0, 1, 2, ..., 9]
result = filter(lambda x: x % 2 == 0, intlist) # 偶数だけを選択
print(intlist)
print(list(result))
このコードでは、整数値を要素とするリストから、偶数の要素だけを抜き出している。これもmap関数と同様に内包表記を使って記述できる。
result = [x for x in intlist if x % 2 == 0]
こちらはif節で、要素を取り出すための条件を指定するところがポイントとなる。実行結果は次の通りだ。
all関数とany関数
最後にall関数とany関数を紹介しておこう。
all関数/any関数
all(iterable)
any(iterable)
all関数は引数に渡した反復可能オブジェクト(リストなど)の全ての要素が「真」と判定された場合にTrueを返す(いずれかの要素が「偽」と判定された場合にはFalseを返す)。any関数は引数に渡した反復可能オブジェクトのいずれかの要素が真と判定された場合にTrueを返す(全ての要素が「偽」と判定されたらFalseを返す)。空の反復可能オブジェクトを渡した場合には、all関数はTrueを、any関数はFalseを戻り値とする。
パラメーター | 説明 |
---|---|
iterable | 全要素が真かどうか(all関数)、またはいずれかの要素が真かどうか(any関数)を調べたい反復可能オブジェクト |
all関数/any関数のパラメーター |
以下に例を示す(実行結果は省略する)。
intlist1 = list(range(5)) # [0, 1, 2, 3, 4]
intlist2 = list(range(1, 6)) # [1, 2, 3, 4, 5]
intlist3 = [0] * 5 # [0, 0, 0, 0, 0]
strlist1 = ['', 'foo', 'bar']
strlist2 = ['foo', 'bar', 'baz']
strlist3 = [''] * 5
emptylist = []
print('all(intlist1):', all(intlist1)) # False:0は「偽」と見なされる
print('all(intlist2):', all(intlist2)) # True
print('all(intlist3):', all(intlist3)) # False:0は「偽」と見なされる
print('any(strlist1):', any(strlist1)) # True
print('any(strlist2):', any(strlist2)) # True
print('any(strlist3):', any(strlist3)) # False:空文字列は「偽」と見なされる
print('all(emptylist):', all(emptylist)) # True:空のリストを渡すと戻り値はTrue
print('any(emptylist):', any(emptylist)) # False:空のリストを渡すと戻り値はFalse
Pythonには「0以外の数値、空でないリストや文字列などは真と見なされる」「数値0や空のリストや文字列などは偽と見なされる」という性質がある。そのため、all関数とany関数では、各要素の値がブール型のTrueかFalseのどちらなのかではなく、それらが真と見なされるか偽と見なされるかを基にその戻り値が決定されることに注意しよう。
all関数とany関数は次のような条件を調べるためのものだ。
- all関数:全ての要素の値が真かどうか
- any関数:いずれかの要素の値が真かどうか
だが、次のような条件が成り立っているかを調べたいこともあるかもしれない。
- 全ての要素の値が「偽」かどうか
- いずれかの要素の値が「偽」かどうか
これらについて少し考えてみよう。
「全ての要素の値が偽」というのは、実は「『いずれかの要素が真』ではない」と読み替えられる。同様に、「いずれかの要素の値が偽」というのは、「『全ての要素が真』ではない」と読み替えられる(真偽を計算する論理は「ブール代数」と呼ばれる理論にまとめられている。ここでの議論はその一部だ)。
そして、「いずれかの要素の値が真」かどうかはany関数で調べられるし、「全ての要素の値が真」かどうかはall関数で調べられる。後は「ではない」という部分を表現できればよい。これには第8回「if文による条件分岐」で紹介した「ブール演算子」のうちの「not」演算子が使える。「not」演算子は「not X」と書いたときに「Xの値が真ならFalse」を、「Xの値が偽ならTrue」をその演算結果とするものだ(真偽を「反転」する)。
上の条件はall関数とany関数の戻り値を「not」演算子で「反転」してやれば分かるということだ。
- 全ての要素の値が「偽」かどうか→「いずれかの要素が真」ではない→not any(……)
- いずれかの要素の値が「偽」かどうか→「全ての要素が真」ではない→not all(……)
最初は少し分かりにくいかもしれないが、TrueやFalseを戻り値とする関数では、「not」演算子と組み合わせることで、元の条件を「反転」した条件を表現できることは覚えておこう。
まとめ
今回のまとめ:リストと繰り返し処理
- for文とリストを組み合わせることで、リストの各要素に対して、反復的な処理を行える
- for文の中でリストの要素を書き換えるには、ループ変数ではなく、インデックスを用いて、リストの要素そのものに新しい値を代入する必要がある
- リストの要素とそのインデックスが必要であれば、enumerate関数を使用する
- 複数のリストの要素をひとまとめにして扱いたいときには、zip関数を使用する
- リストは「反復可能オブジェクト」(イテラブル)の一種であり「一度に1つの要素を取り出せる」オブジェクト
- これに対して「イテレータ」は「データの流れ」を表現するオブジェクト
- リストの要素にアクセスするための「イテレータ」を使うことで、for文の内部では反復可能オブジェクトとイテレータを透過的に扱えるようになっている
- map関数はリストの要素に何らかの処理を適用した結果を要素とするイテレータを戻り値とする
- filter関数はリストの要素に何らかの処理を適用して、その結果が真となるものだけを要素とするイテレータを戻り値とする
- map関数とfilter関数で行う処理はリスト内包表記でも表現できる
- リストの全要素の値が「真」かどうかはall関数で判定できる
- リストのいずれかの要素の値が「真」かどうかはany関数で判定できる
- all関数/any関数と「not」演算子を組み合わせることで、「いずれかの要素の値が偽」かどうかや「全要素の値が偽」かどうかも判定できる
「Python入門」
Copyright© Digital Advantage Corp. All Rights Reserved.