2008年10月1日水曜日

Python でネストしたリストから Composite パターンを生成

Python でリストに対する再帰的な関数の適用」では、ネストしたリストに対して、リストのまま関数を適用した。今回はネストしたリストから Composite パターンとなるようにオブジェクトを生成してみる。 Composite にしておけば、後々の操作がしやすくなるかな。

 

Composite パターン

リストを、オブジェクトを使って次のような構造へ変換する。とりあえず、リスト → オブジェクトへの変換だけなので、要素に相当するクラスは作らない。リストを表わす List クラス、値を表わす Value クラスのみを作成。要素クラスは、List, Value に共通の操作が必要になったときに作成することに。

080930-001

 

まずは、List と Value クラス。

class List:
    BRACKETS = "<>"

    def __init__(self):
        self.elems = []

    def add(self, elem):
        self.elems.append(elem);
        return self

    def __str__(self):
        return List.BRACKETS[0] + \
               ",".join(str(e) for e in self.elems) + \
               List.BRACKETS[1]

    def __iter__(self):
        return iter(self.elems)

class Value:
    def __init__(self, val):
        self.val = val

    def __str__(self):
        return str(self.val)

( cf. Python のイテレータ, Python のイテレータ (3) )

 

Composite を生成する関数

リストからオブジェクトを生成する関数は、前回の再帰的な関数を真似る。

  1. 渡されたリストがリストであれば、要素に対して再帰的に生成関数を適用する。
  2. 値であれば、 Value クラスを作成。
def createList(L):
    if isinstance(L, list):
        newList = List()
        for e in L:
            newList.add(createList(e))
        return newList
    else:
        return Value(L)

 

List クラスに要素を追加するメソッドは、最後に自身を返すようにしているので、reduce で書換えることができる。

def createList(L):
    if isinstance(L, list):
        return reduce(lambda a,b: a.add(createList(b)), L, List())
    else:
        return Value(L)

print createList([1,2,[21,22,[231],24,1],2,3,4,5])

上記を実行した結果は、

<1,2,<21,22,<231>,24,1>,2,3,4,5>