リスト内包表記



リスト内包表記とは、あるリストを元にして別のリストを作るための記法のことです。ループ、Map、Filterなどを使っても同じ操作をできますが、リスト内包表記には以下の利点があります。

  1. コードがシンプルになる
    ⇒行数へります。
  2. 可読性が高まる
    ⇒慣れてしまえば読みやすいです。
  3. 実行速度が高速
    ⇒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の内包表記はなぜ速い?


Facebook comments:

comments

Leave a Reply


Get Adobe Flash player