概要
Clean Coder を立ち読みして、コード型の考え方が自分に合ってそうだったのでやってみる。
カタは空手の型から来ているらしい。
基礎練とかそういうの好きなので、こういう地味な基礎練的なのは自分に合っている。と思う。
今回のお題
お題はCodingDojoというサイトから取ってくる。
今回はAnagramをやってみる。
課題
標準入力で単語を受け取って、アナグラムを二つ作って返す。
- 例)
scheme -> chesem, hcemse
使用言語
今回はなんとなく好きなschemeでやってみる。
(シンプルに書けて考え方がわかりやすいと思ったので)
- 今回使用した環境
- gauche 0.9.5
ちなみにgaucheはscheme処理系の一つ。
他の処理系(racketとか)より機能が充実してて便利なので、schemeやるならオススメ。らしい。
解いてみる
schemeで受け取った文字列を変換し、アナグラムを作って出力させる関数を作る。
schemeでこれをプログラミングする時、次の2つを考える必要がある。
-
受け取った文字列をリスト化する
-
ランダムにアナグラム化するロジックを考える必要がある。
-
でリスト化することはそれほど難しくない。
schemeの文字列はダブルクォートで囲むことで作成できる。
gosh> (define s "scheme")
gosh> (string? s)
# t
文字列から一文字づつ取り出してconsしてリスト化しようと思ったけど、
string->listで文字列をリスト化できるのでこっちを使う。
gosh> (define slist (string->list s))
slist
gosh> slist
(#\s #\c #\h #\e #\m #\e)
gosh> (pair? slist)
# t
2.の方がいまいち思いつかない。
乱数を使って文字列から一文字づつ取り出し、consするとかだろうか…
と思ったらすでに関数があった。
ここのshuffleという関数を使う。
これを使うためにuseマクロでgauche.sequenceを取り込む
gosh> (use gauche.sequence)
これはrequireしてimportするのと同じ
gosh> (require "gauche/sequence")
gosh> (import gauche.sequence)
requireすることで、別ファイルの関数を読み込み、評価し、importすることで変数や関数を取り込んで使える様にしている。
gosh> (shuffle slist)
(#\c #\h #\e #\e #\s #\m)
gosh> (shuffle slist)
(#\m #\s #\e #\c #\e #\h)
最後にlistをstringに戻す。listをstringに戻すにはlist->stringを使う
gosh> slist
(#\s #\c #\h #\e #\m #\e)
gosh> (list->string slist)
"scheme"
shuffleした結果をlist->stringで元に戻すにはこう書く。
gosh> (list->string (shuffle slist))
"echmes"
gosh> (list->string (shuffle slist))
"cemehs"
これでできそう。コードを書いてみる。
;; 受け取った文字列をランダムでアナグラム化する
;; shuffle用にmoduleをインポートする
(use gauche.sequence)
(define (anagram str)
(let ((slist (string->list str)))
(let ((agm1 (list->string (shuffle slist)))
(agm2 (list->string (shuffle slist))))
(list agm1 agm2))))
実行結果は下記の通り
gosh> (anagram "scheme")
("meshec" "ceehsm")
ここでは、返却値をアナグラムした結果のリストにした。(テスト可能なコードにするため)
テストする
さらに、テストコードを書いていく。テストの合格条件は以下2つ。
- 返却したリストの要素数が2つであること
- リストの文字列が引数のアナグラムであること
1.は簡単。リストの要素数をlengthで調べれば良い。
gosh> (length (anagram "scheme"))
2
2.の方が重要。ここでは、引数とアナグラムの結果両方をソートして比較する。
sortを使えば、文字列もソートしてくれる。
gosh> s
"scheme"
gosh> (sort s)
"ceehms"
アナグラムの結果もsortする。結果は同じになる。
gosh> (define anagram-list (anagram "scheme"))
anagram-list
gosh> anagram-list
("escmeh" "cmsehe")
gosh> (sort (car anagram-list)) ;; "escmeh"をソート
"ceehms"
gosh> (sort (cadr anagram-list)) ;; "cmsehe"をソート
"ceehms"
これらを使ってテストコードを書く。テストにはgauche.testを使う。
testディレクトリを作成して、その中にテストコードを放り込む。ディレクトリ構成はこんな感じ
.
├── anagram.scm
└── test
└── anagram-test.scm
テストコードはこう書く。
(use gauche.test)
(test-start "anagram")
(load "../anagram.scm")
;; テスト用にアナグラム結果のリストを作る。
(define str "scheme")
(define test-anagram-list (anagram str))
(test-section "anagram-test")
;; アナグラム結果が2つであることをテスト
(test* "number of anagram list" 2 (length test-anagram-list))
;; アナグラムが正しくできていることのテスト
;; 比較用に引数をsortした文字列を用意
(define sorted-str (sort str))
(test* "anagram 1" sorted-str (sort (car test-anagram-list))) ;; 一つ目のテスト
(test* "anagram 2" sorted-str (sort (cadr test-anagram-list))) ;; 二つ目のテスト
(test-end)
テスト結果
gosh> Testing anagram ...
# <undef>
gosh> #t
gosh> str
gosh> test-anagram-list
gosh> <anagram-test>-----------------------------------------------------------------
# <undef>
gosh> test number of anagram list, expects 2 ==> ok
# <undef>
gosh> sorted-str
gosh> test anagram 1, expects "ceehms" ==> ok
# <undef>
gosh> test anagram 2, expects "ceehms" ==> ok
# <undef>
gosh> passed.
0
所感
あんまり大したことやってないけどどうせなのでまとめてみた。
今回はライブラリに頼りすぎてて自分で考えてない感が強いので、次はもっとゴリゴリ書いてみたい。
参考
-
Coding Dojo kata
- いろんなお題があって見てるだけで楽しい。
-
Gauche ドキュメント
- Gaucheのことで困ってたらここを見れば大体載ってた。助かった。