1. リストを操作する関数で重要なのはどれ?
リスト内包表記は慣れたら使いやすい
Python のリスト内包表記に出会って 4 ヶ月が経った。
「Python のリスト内包表記」を読みなおしてみると、
… 同じく数値のリストから、特定の条件に合う要素を抽出する。
print [x for x in [1,2,3,4,5] if x > 3]これまた読みにくい。 (@_@;)
と書いていたけれど、今では「シンプルで読みやすく、また書きやすい」と思える。慣れとは恐ろしい。 ^^;
(リスト内包表記がネストしてたりすると、すぐに理解出来ないけれど。)
Ruby の Enumerable モジュールにはたくさんのメソッドが定義されている
Java しか知らなかった頃、Ruby の 配列に定義されているメソッドを見て、「便利なメソッドがたくさんあるなぁ」と思った。Ruby の配列は、Enumerable モジュールをインクルードしており、そこにいくつかメソッドが定義されている。
配列だけではなく、自分でクラスを定義した場合でも、 Mix-in の機能により、each を定義するだけで簡単にパワーアップ。
しかし、 Enumerable モジュールに定義されている、20個程度のメソッドを見ても、どれが重要なのかわからない。 (@_@;)
sort メソッド以外では、
- each
- each_with_index
ばかりに目が行ってしまい、
- map
- select
- inject
なんて便利なんだけど脇役だと思ってた。
Haskell, Python でも同じような関数が定義されている
Haskell, Python を触るようになって、上記の印象が変わった。両方とも、リスト内包表記が特別に用意されている言語。
例えば、Haskell の Prelude の目次を見ると、List operations として真っ先に map が定義されている。リストの結合(++) に続いて filter , 少し間を空けて、Reducing lists (folds) がある。
あ~、なるほど、これらが重要な関数なんだと理解できた。
map, filter, reduce 関数が重要だと認識しても、昔からの慣習の力はすごい。 (+_+) リストの要素に関数を適用することを考える場合、for ループで要素を走査するイメージのしやすは、コードを書くときのの強力な引力として働く。
for ループを書くこと自体、別に悪くない。しかし、面倒くさがりやなので、お決まりのコードはなるべく短く書きたい。そこで、for ループとの対応を明確にして、map, filter, reduce 関数の使い方を練習しておく。できれば、リスト操作を考えるとき、ループをイメージするのを飛びこして、 map, filter, reduce へと思考がダイレクトに反応することを願って。 o(^^)o
2. リスト全体に対する計算 : reduce
合計
リストを走査して合計を求める。
L = [1,2,3,4,5] result = 0 for e in L: result += e print result
以後、リスト L を使う。
reduce を使えば、
print reduce(lambda a,b: a+b, L)
合計に関しては特別に、
print sum(L)
総乗
result = L[0] for e in L[1:]: result *= e print result
reduce を使えば、
print reduce(lambda a,b: a*b, L)
リストの要素全体に渡って、何らかの演算をした結果を積立てていきたいときは reduce を思い出すこと。
(1+2)+3)+4)+5)
3. リストの要素に演算を適用 : map
例えば、要素を 2 倍する
result = [] for e in L: result += [e*2] print result
map, リスト内包表記を使うと、それぞれ、
print map(lambda x: x*2, L) print [x*2 for x in L]
reduce を使うなら、
print reduce(lambda a,b: a+[b*2], L, [])
空のリストを初期値として渡し、要素に対して演算を適用した後はリストにするところがポイント。
4. リストの要素を抽出 : filter
例えば、 3 より大きい要素を得る場合、
result = [] for e in L: if e > 3: result += [e] print resultfilter, リスト内包表記を使うなら、 それぞれ、
print filter(lambda x: x>3, L) print [x for x in L if x > 3]
reduce を使うなら、
print reduce(lambda a,b: a+[b] if b > 3 else [], L, [])
空のリスト[] をリストに足しても変わらないことがポイント。
5. リストの要素を抽出して演算を適用 : filter と map
例えば、3 より大きい要素を得て 2 倍する
result = [] for e in L: if e > 3: result += [e*2] print result
filter と map 、リスト内包表記を使うと、それぞれ
print map(lambda x: x*2, filter(lambda x: x > 3, L)) print [x*2 for x in L if x > 3]
reduce を使うなら、
print reduce(lambda a,b: a+[b*2] if b > 3 else [], L, [])
やはりリスト内包表記はシンプルでいい。 ^^