メモ: groupbyと、3つ目の引数が0のreduce関数
finalfusionさんにコメントで書いて頂いたコードを把握したときの備忘メモです。
for e in itertools.groupby(data_list, key=lambda z:z.code): print(e[0], functools.reduce(lambda a,b:a+b, [x.value for x in e[1]], 0))
(これをぱっと見で理解できるレベルにまだないわけです…)
ポイントは、
- itertools.groupbyの戻り値
- 初期値を持つreduce関数
の2つです。
itertools.groupbyの戻り値
groupby() は、下敷きになっているイテラブルから、連続して同じキー値を持つ要素を集めて、キー値とイテレータの 2-タプルを返していきます。
http://www.python.jp/doc/nightly/howto/functional.html
groupbyは、キー(e[0])と、要素へのイテレータ(e[1])を要素に持つタプルを返し続けます。
次のページでは、groupbyの結果について、
keyfunc(v) の値でグループ化したサブイテレータ
http://www.python.jp/doc/nightly/library/itertools.html
と書いてあり、サブ???という感じでしたが、上の記述で分かりました。
初期値を持つreduce関数
reduceの引数の0って何だろうと思ったら、チュートリアルに解説がありました。
3 つめの引数をわたして、初期値を指定することもできます。この場合、空のシーケンスを渡すと初期値が返されます。それ以外の場合には、まず初期値とシーケンス中の最初の要素に対して関数が適用され、次いでその結果とシーケンスの次の要素に対して適用され、以降これが繰り返されます。例えば以下のようになります。
http://www.python.jp/doc/release/tutorial/datastructures.html
def sum(seq): def add(x,y): return x+y return reduce(add, seq, 0) sum(range(1, 11)) 55 sum([]) 0
lambdaを使って上のsum関数を書き換えると、こうなるでしょう。
def sum(seq): return reduce(lambda x,y:x+y, seq, 0)
おっ…。冒頭のコードに近い形になりました。
このreduceは、初期値0+seq[1]、(初期値0+seq[1])+seq[2]…という具合に、戻り値を作っていきます。
つまり、冒頭のコードは、ある値をキーにする集合(setの要素に該当するモノ)であるところのe[1]に対して、その処理を行っているわけですね。
なるほど。やっと理解できましたw ありがとうございます。