はじめに
Rubyのjoinみたいな関数がないので勉強のため書いてみました。
セパレータを挟んで連結する関数はRubyを使うときに、よく使用するのであれば便利だと思いました。
joinとは
Rubyの他にも様々な言語で実装されていると思いますが、今回はRubyを例にします。
処理内容は配列を受け取り、区切り文字で連結した文字列を返すというものです。
例として下にソースコードを示します。
join.rb
[1, 2, 3, 4].join(",") # => "1,2,3,4"
['a', 'b', 'c', 'd'].join("=") # => "a=b=c=d"
例のように配列を指定した区切り文字で連結して文字列を返しているのが分かります。
Rubyの実装では配列が入れ子になったものも平滑化して、関数を適用してくれます。Lispではリストの平滑化を行うflattenという関数を定義し、その関数を適用したリストを今回作成した関数に渡すと可能です。
ソースコード
join.lisp
(defun join (list sep)
(with-output-to-string (s)
(labels ((fn (list)
(cond ((null (cdr list)) (princ (car list) s))
(t (princ (car list) s)
(princ sep s)
(fn (cdr list))))))
(fn list))))
;=> JOIN
(join '(1 2 3 4) ",")
;=> "1,2,3,4"
(join '(a b c d) "=")
;=> "A=B=C=D"
(join '(a b c d) "===")
;=> "A===B===C===D"
おわりに
loopとformatで出来ると思ったのですが、最後に余計な区切り文字が入り、それを取り除く方法が分からなかったので諦めてしまいました。
Lispを勉強する前はループでまず解決しようと考えていたのですが、Lispを勉強し始めて再帰をまず使うような思考に切り替わったような気がします。
追記
doによるループでも実装してみました。
join_do.lisp
(defun join (list sep)
(with-output-to-string (s)
(do ((elem list (cdr elem)))
((null (cdr elem)) (princ (car elem) s))
(princ (car elem) s)
(princ sep s))))
;=> JOIN
(join '(1 2 3 4) ",")
;=> "1,2,3,4"
(join '(a b c d) "=")
;=> "A=B=C=D"
(join '(a b c d) "===")
;=> "A===B===C===D"