« 日記 |Main| YAMLベースの新しいフォーマット »

« Pythonのジェネレータで四角いらせんを書いた | Python | 一般化したハノイの塔問題にひそむ規則性 »

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  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)
もちろん、人間に読みやすく改行は入れてあるものの、本質的に一つの文で書けるので、こう書いてもOK(ぇ) 不必要なスペースを取り除けばまだまだ縮みますよー。

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/409

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.