Re: Re: Pythonのジェネレータで四角いらせんを書いた
逃走航路@hatena - Re:Pythonのジェネレータで四角いらせんを書いた:西尾泰和のブログにお返事。
元の記事が「アルゴリズムを確認するためにPythonでわかりやすく書いてからJavaで書く」という趣旨であることをはおいといて、やっぱりよく似たフレーズが4回も繰り返してあるとまとめたくなるのはプログラマの性ですよね。僕なら同じ手続きは以下のように関数にまとめて、
>>> def squareSpiral(): width = 0 p = (0, 0) yield p ops = [ lambda (x, y), d: (x + d, y), lambda (x, y), d: (x, y + d) ] while True: width += 1 for i in range(width): p = ops[0](p, 1) yield p for i in range(width): p = ops[1](p, 1) yield p width += 1 for i in range(width): p = ops[0](p, -1) yield p for i in range(width): p = ops[1](p, -1) yield pその関数を順番に使っている部分はforにまとめ、
>>> def squareSpiral(): width = 0 p = (0, 0) yield p ops = [ lambda (x, y), d: (x + d, y), lambda (x, y), d: (x, y + d) ] while True: width += 1 for op in ops: for i in range(width): p = op(p, 1) yield p width += 1 for op in ops: for i in range(width): p = op(p, -1) yield p関数の引数が異なるだけの部分もforでまとめます。
>>> def squareSpiral(): width = 0 p = (0, 0) yield p ops = [ lambda (x, y), d: (x + d, y), lambda (x, y), d: (x, y + d) ] while True: for d in [1, -1]: width += 1 for op in ops: for i in range(width): p = op(p, d) yield pあ、でも縮んでない…。 縮ませるためにはやっぱり破壊的メソッドを使って代入を消しておいて、
>>> def squareSpiral(): width = 0 p = [0, 0] yield tuple(p) ops = [ lambda p, d: p.__setitem__(0, p[0] + d) or p, lambda p, d: p.__setitem__(1, p[1] + d) or p ] while True: for d in [1, -1]: width += 1 for op in ops: for i in range(width): yield tuple(op(p, d))最後に残った重複(ops)もforでまとめる。
def squareSpiral():
width = 0
p = [0, 0]
yield tuple(p)
ops = [(lambda k:(lambda p, d: p.__setitem__(k, p[k] + d) or p))(k) for k in [0, 1]]
while True:
for d in [1, -1]:
width += 1
for op in ops:
for i in range(width):
yield tuple(op(p, d))
あっ。でもJava側のコードみたいに「次に進める関数」を作ってこう書く手もありますね。
>>> lambda x, y, width, i, phase: [ [0, 0, 1, 0, 1], [ x + 1, y, width, [i + 1, 0][i + 1 == width], [1, 2][i + 1 == width] ], [ x, y + 1, width + [0, 1][i + 1 == width], [i + 1, 0][i + 1 == width], [2, 3][i + 1 == width] ], [ x - 1, y, width, [i + 1, 0][i + 1 == width], [3, 4][i + 1 == width] ], [ x, y - 1, width + [0, 1][i + 1 == width], [i + 1, 0][i + 1 == width], [4, 1][i + 1 == width] ]][phase] <functionもちろん、人間に読みやすく改行は入れてあるものの、本質的に一つの文で書けるので、こう書いてもOK(ぇ) 不必要なスペースを取り除けばまだまだ縮みますよー。at 0x012AF770> >>> args = [0, 0, 0, 0, 0] >>> (globals().__setitem__("args", f(*args)) or tuple(args[:2]) for i in range(10)) <generator object at 0x00DAA6E8> >>> for p in _: print p (0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) (2, -1)