《余録》Swing/Jython - 再帰 vs. reduce
Java プログラマーのための Python 導入ガイド《記事一覧》
《余録》再帰 vs. reduce
■ 概要
フォルダー/ファイルの階層構造を Swing/GUI を利用して「簡単に」閲覧できるツールがあると便利です。
セミナー課題では、JTree/DefaultMutableTreeNode と同等の機能を「実現する」方法を紹介しました。 ここでは、入門者向けに、既存の機能を「利用する」方法を紹介するとともに、その問題点について考察します。 《Note》JPython1.1.x/Jython2.1.x 用に作成したセミナー課題を、Jython2.5 で再構成しました。
■ 関連記事
- Java/Python 導入ガイド:Swing/Jython2.5 - JTree - 続・ひよ子のきもち, Swing/Jython - JTree
事例:階乗
■ factorial:再帰版
再帰呼び出しで必須になるのは「停止条件」です。「再帰呼び出しをいつ止めるか」を判定する条件が不適切だと、永遠に処理を繰り返す(無限ループに陥る)ことになります。
def fact(n): if n<2: return 1 return n*fact(n-1)
関数 fact は、指定した引数 n の階乗を求めるもので、if に続く条件式 n<2 が停止条件です。
■ factorial:reduce 版
組み込み関数を利用すると、再帰呼び出しに伴う「停止条件」が不要になり、簡潔で見通しの良いコードを記述できるようになります。
def fact(n): return reduce(lambda s,e: s*e, range(n,1,-1), 1)
ここでは、変数 n の値が 2 未満なら、空のリストが得られるので、lambda 式を一度も実行しません。そして、式の本体にある s*e が、再帰呼び出しに相当します。
■ factorial:for..in 版
for 文でも同じ結果は得られますが、reduce と比べて、やや冗長な表現を余儀なくされます。
def fact(n): s = 1 for e in range(n,1,-1): s *= e return s
ここでも、変数 n の値が 2 未満なら、for ブロックを一度も実行しません。そして、ブロック本体にある s *= e が、再帰呼び出しに相当します。
事例:課題
セミナー課題では、再帰的な構造を取り扱いたいときに、reduce を積極的に活用しています。
■ イテレーター:__iter__
組み込み関数 iter に呼応して、各要素を参照するイテレーターが得られます。
class DirNode(Node): # Composite::Composite def preorder(self): return reduce( lambda s,e: s+e.userObject.preorder(), self.node.children(), [self])
メソッド preorder は(preorderEnumeration と同様に)その傘下にある各ノードを「前順走査」します。
ここでも、self.node.children() が空リスト(で子を持たない)なら、lambda 式を一度も実行しません。そして、式の本体にある e.userObject.preorder() が、再帰呼び出しに相当します。
■ イテレーター:インデント
メソッド indents を利用すると、各ノードのインデントを返すイテレーターが得られます。
class DirNode(Node): # Composite::Composite def indents(self, indent=0): return reduce( lambda s,e: s+e.userObject.indents(indent+1), self.node.children(), [indent])
メソッド indents は、その傘下にある各ノードのインデント(深さ)を「前順走査」します。
ここでも、self.node.children() が空リスト(で子を持たない)なら、lambda 式を一度も実行しません。そして、式の本体にある e.userObject.indents(indent+1) が、再帰呼び出しに相当します。
⇒ 続きはこちら 》〈GoF〉Iterator を実現する《 で