gaucheで行列


「Ruby力向上のための基礎トレーニング」をCommon Lispで解いてみた を見て、Gauche で書いてみようと思った。

で、試してみたけど、リスト操作でやるのがイマイチイメージできなかったのと、 むしろ良くあるインデックスアクセスの方が簡単じゃないか、と思ったので、 そっち方面から攻めてみた。

gauche.array を用いたスクリプト

以下の様になった

#!/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 みたいな階層構造を持つデータ形式だと親和性が高いと思う。 頂点を取り換えながら再帰するとか、自然に書けるし。