リスト内包表記
リスト内包表記とは、あるリストを元にして別のリストを作るための記法のことです。ループ、Map、Filterなどを使っても同じ操作をできますが、リスト内包表記には以下の利点があります。
- コードがシンプルになる
⇒行数へります。 - 可読性が高まる
⇒慣れてしまえば読みやすいです。 - 実行速度が高速
⇒forループと比べて2倍程度高速です。
Pythonを使うのであれば早めにマスターしておかないと後悔しますよ!では、さっそく使ってみましょう!
リスト内の要素を2倍にする
リスト内の値を2倍にします。リスト [1,2,3,4,5] から、リスト [2,4,6,8,10] を作る操作です。
ループ
ループを使った“普通”なやりかたです。Pythonユーザにとっては異常なやり方です。
1 2 3 4 5 6 | >>> B = [] >>> for num in A: ... B.append(num*2) ... >>> B [2, 4, 6, 8, 10] |
map (関数を使った場合)
PHPでarray_map使うとこんな感じになりますね。
1 2 3 4 5 | >>> def double(x): ... return x*2 ... >>> map(double, A) [2, 4, 6, 8, 10] |
map (ラムダ式を使った場合)
Lisp系の言語になれてれば違和感ないですね。PHP5.3以降でも使えます。
1 2 | >>> map((lambda x: x*2), A) [2, 4, 6, 8, 10] |
リスト内包表記
Pythonian (Python使いの人) はこう書きます。シンプルです。
1 2 | >>> [x*2 for x in A] [2, 4, 6, 8, 10] |
偶数だけ取り出す
リスト内の偶数値だけを取り出します。リスト [1,2,3,4,5] から、リスト [2,4] を作る操作です。
ループ
ループを使った“普通”なやりかたですが、これもPythonianにとっては異常なやり方です。
1 2 3 4 5 6 7 | >>> B = [] >>> for num in A: ... if num % 2 == 0: ... B.append(num) ... >>> B [2, 4] |
filter (関数を使った場合)
値の取捨選択は、mapじゃなくてfilterを使います。
読みやすいですが長いです。
1 2 3 4 5 | >>> def isEven(num): ... return num % 2 == 0 ... >>> filter(isEven, A) [2, 4] |
filter (ラムダ式を使った場合)
短くなりましたが、少し読みづらいです。
1 2 | >>> filter((lambda x: x % 2 == 0), A) [2, 4] |
リスト内包表記
Pythonian はこう書きます。慣れてしまえば簡単です。
1 2 | >>> [x for x in A if x % 2 == 0] [2, 4] |
偶数だけ取り出して2倍にする
リスト内の偶数値だけを取り出して2倍にします。リスト [1,2,3,4,5] から、リスト [4,8] を作る操作です。
ループ
1 2 3 4 5 6 7 | >>> B = [] >>> for num in A: ... if num % 2 == 0: ... B.append(num * 2) ... >>> B [4, 8] |
filter (関数を使った場合)
定義済みの関数を使ってしまえば楽ですね。
1 2 | >>> map(double, filter(isEven, A)) [4, 8] |
filter + map (ラムダ式を使った場合)
1行で記述できますが、括弧が多くて読みづらいです。
1 2 | >>> map((lambda x: x * 2), filter((lambda x: x % 2 == 0),A)) [4, 8] |
リスト内包表記
リスト内包表記だとこうなります。簡潔です。
1 2 | >>> [x * 2 for x in A if x % 2 == 0] [2, 4] |
おまけ
リスト内包表記の元リストに、直接リストを記述
1 2 3 4 | >>> [x * 2 for x in [1,2,3,4,5]] [2, 4, 6, 8, 10] >>> [x * 2 for x in [1,2,3,4,5] if x % 2 == 0] [4, 8] |
結果に対してさらにリスト内包表記を記述
1 2 | >>> [x for x in [x ** 2 for x in [1,2,3,4,5,6,7,8,9,10]] if x < 50] [1, 4, 9, 16, 25, 36, 49] |
タプル(tuple)に引数にとる
1 2 | >>> [x for x in (1,2,3,4,5)] [1, 2, 3, 4, 5] |
入れ子構造のリストを処理
演算対象がリストになってしまう。
1 2 | >>> [x * 2 for x in [[1,2],[2,3]]] [[1, 2, 1, 2], [2, 3, 2, 3]] |
中の要素に対して処理する場合は、リスト内包表記の中にリスト内包表記を記述する。
1 2 | >>> [[y * 2 for y in x] for x in [[1,2],[2,3]]] [[2, 4], [4, 6]] |
九九の表を作る
1 2 3 4 5 | >>> [[x * y for y in range(1,10)] for x in range(1,10)] [[1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10, 12, 14, 16, 18], [3, 6, 9, 12, 15 , 18, 21, 24, 27], [4, 8, 12, 16, 20, 24, 28, 32, 36], [5, 10, 15, 20, 25, 30, 3 5, 40, 45], [6, 12, 18, 24, 30, 36, 42, 48, 54], [7, 14, 21, 28, 35, 42, 49, 56, 63], [8, 16, 24, 32, 40, 48, 56, 64, 72], [9, 18, 27, 36, 45, 54, 63, 72, 81]] |
リスト内包表記は速い
リスト内包表記は、forループと比べて一般的に2倍程度高速だそうです。ただし、ループ内で行う処理自体が重い場合は、ループを高速化してもほとんど意味がありません。数値解析や、フレームワークの構築などであれば速度面のメリットは大きいと思いますが、一般的なWebアプリケーションを作成する際は、性能面のメリットを気にする必要はないと思います。
リスト内包表記は、リストに対する簡単な操作は理解しやすいのですが、複雑な処理をしようとすると急激に読みづらくなっていきます。九九の表を作るの例などは、リスト内包表記に慣れていない人には読み辛いと思います。せっかくPythonを使っているのだから、読みやすさ、わかり易さを重視しましょう。無理をしてまでリスト内包表記をつった結果、読み辛いソースコードになってしまっては本末転倒です。
参考: リスト内包表記の性能について
Pythonの内包表記はなぜ速い?