mapとreduce

map

まずは標準的な使い方。

>>> map((lambda x: x ** 2), [1,2,3,4,5])
[1, 4, 9, 16, 25]

面白いのは、引数にリストを複数とれること。この場合、Haskell の zipWith 相当の動作をする。

>>> map((lambda x,y: x + y), [1,2,3,4,5], [10,20,30,40,50])
[11, 22, 33, 44, 55]

リスト3つでもいける。

>>> map((lambda x,y,z: x * y + z), [1,2,3,4,5], [6,7,8,9,10], [10,20,30,40,50])
[16, 34, 54, 76, 100]

いくつまでいけるのかは確認してない。

reduce

mapときたらreduce。injectでもfoldlでもなくreduce。何でこう、畳み込み関数って言語によって名前が違うんだろう。

>>> reduce((lambda x,y: x * y), [1,2,3,4,5], 1)
120

第3引数は省略可能で、そのときはリストの最初の値が初期値になるみたい。

>>> reduce((lambda x,y: x * y), [1,2,3,4,5])
120

この例の場合だと結果は同じだ。

追記:こういう例のほうが初期値の有無による動作の違いがわかりやすい:

>>> reduce((lambda x,y: (x,y)), [1,2,3,4,5], 0)
(((((0, 1), 2), 3), 4), 5)
>>> reduce((lambda x,y: (x,y)), [1,2,3,4,5])
((((1, 2), 3), 4), 5)

関数に関数を渡す

リストのsortメソッドには、比較用の関数を渡すことができる。
まずは何も渡さない場合:

a = ["abc", "def", "BCD", "EFG"]

a.sort()
print a
^o^ > python sort.py
['BCD', 'EFG', 'abc', 'def']

比較用の関数を渡さないと、ASCII順にソートされている。次は小文字に変換してから比較する関数を渡してみる。

a = ["abc", "def", "BCD", "EFG"]

def cmp_lower(a, b):
    return cmp(a.lower(), b.lower())

a.sort(cmp_lower)
print a

実行結果:

^o^ > python sort2.py
['abc', 'BCD', 'def', 'EFG']

大文字小文字を無視した順になった。

こんな風に関数に関数を渡すことができる。Pythonでは関数は第一級のオブジェクトだったことだな。

じゃあ、関数を返すことはできるのか。

def foo():
    print "foo"
    def bar():
       print "bar"
    return bar

bar = foo()
bar()

foo関数のなかでbar関数を定義して、それをreturnしている。実行すると:

^o^ > python return_function.py
foo
bar

予想通りの結果になった。最初の出力 foo はfoo関数の実行中に出力されたもの。次の bar はfoo関数から返ってきた関数を呼び出したときに出力されたものだ。

Pythonでは関数に関数を渡すことも、関数を返すこともできる。

forループ

forループは、「for 変数 in シーケンス」という形をしている。シーケンスとはリスト、タプル、文字列の総称みたいなもの。

リストでの例:

>>> for i in [1,2,3,4,5]:
...     print str(i) + ":" + "Hello" * i
...
1:Hello
2:HelloHello
3:HelloHelloHello
4:HelloHelloHelloHello
5:HelloHelloHelloHelloHello

タプルの例:

>>> for t in ('Foo', 'Bar', 'Baz'):
...     print t
...
Foo
Bar
Baz

文字列でもいける:

>>> for c in "abcde":
...     print c
...
a
b
c
d
e

setだとどうか:

>>> for c in set(['a', 'b', 'c']):
...     print c
...
a
c
b

いけた。

if ~ elif ~ else

Python での条件分岐。これも関数と同じくブロックをインデントであらわしている。
例は引数の大小で出力が変化する。

import sys

num = int(sys.argv[1])

if num < 10:
    print "smaller than 10."
elif 10 < num:
    print "bigger than 10."
else:
    print "just 10."

引数は文字列なのでint関数を使って整数に変換している。

実行結果:

^o^ > python if.py 3
smaller than 10.

^o^ > python if.py 16
bigger than 10.

^o^ > python if.py 10
just 10.