「Ruby力向上のための基礎トレーニング」をCommon Lispで解いてみた を見て、Gauche で書いてみようと思った。
で、試してみたけど、リスト操作でやるのがイマイチイメージできなかったのと、 むしろ良くあるインデックスアクセスの方が簡単じゃないか、と思ったので、 そっち方面から攻めてみた。
以下の様になった
#!/usr/bin/env gosh
;; -*- coding: utf-8 -*-
(use gauche.array)
(define INPUT
'((9 85 92 20)
(68 25 80 55)
(43 96 71 73)
(43 19 20 87)
(95 66 73 62)))
(define INPUTA
#,(<array> (0 5 0 4) 9 85 92 20 68 25 80 55 43 96 71 73 43 19 20 87 95 66 73 62)
)
(define OUTPUTA
(make-array (shape 0 6 0 5) 0)
)
(define (main args)
(let ((x (array-length INPUTA 0)) (y (array-length INPUTA 1)))
(array-for-each-index
INPUTA
(lambda (i j)
(array-set! OUTPUTA i j (array-ref INPUTA i j))
(array-set! OUTPUTA x j
(+ (array-ref OUTPUTA x j) (array-ref INPUTA i j)))
(array-set! OUTPUTA i y
(+ (array-ref OUTPUTA i y) (array-ref INPUTA i j)))
(array-set! OUTPUTA x y
(+ (array-ref OUTPUTA x y) (array-ref INPUTA i j)))
))
)
(print "result: " OUTPUTA)
0)
for-each なループがあったので 2 重ループにしなくて済んだ。 それでもアクセスは 2 次元として実行している。 結果、見やすくなったと思う。
元ページのやり方を良く見てみた
ポイントは「行を列に変換する」事。
1 行を扱うのは通常のリスト処理と同じ。で、縦方向の処理は配列全体を 裏返して横方向で処理できる様にする。
あとは裏返しをもう一度実行して元に戻す。
発想の飛躍具合はスゴいと思う。けど、効率とか。うーんってなる。
sxml みたいな階層構造を持つデータ形式だと親和性が高いと思う。 頂点を取り換えながら再帰するとか、自然に書けるし。