2015/09/21
プログラミングGauche 9.1練習問題
delete-1
は見つからなかった場合もcond式のelse節でconsしているためにコピーしたリストを返す.
元のリストを返すように実装する.
以下が元のdelete-1
(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
(define (loop lis)
(cond [(null? lis) ()]
[(cmp-fn (car lis) elt) (cdr lis)]
[else (cons (car lis)
(loop (cdr lis)))]))
(loop lis)))
cond
をつかった実装.
(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
;; 見つけた場合の処理
(define (loop lis)
(cond [(cmp-fn (car lis) elt) (cdr lis)]
[else (cons (car lis)
(loop (cdr lis)))]))
;; member関数で要素があるか探す
(cond [(and (member elt lis cmp-fn) #t) (loop lis)]
[else lis])))
見つからない場合の処理はすでにmember
で行ってるのでnull?
は省略.
(cond [(and (member elt lis cmp-fn) #t) (loop lis)]
の部分が少しわかりにくい.
member
は要素が見つからなかった場合に元のリストを返すのでand
に入れてリストが返って来た場合は#t
を,#f
が返ってきた場合は#f
を返すようにした.
if
をつかった実装
(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
;; 見つけた場合の処理
(define (loop lis)
(if (cmp-fn (car lis) elt)
(cdr lis)
(loop (cdr lis))))
;; member関数で要素があるか探す
(if (member elt lis cmp-fn)
(loop lis)
lis)))
if
ならリストが返って来た場合もthen
節を実行してくれる.
member
で末尾再帰で探した後にdelete-1
で非末尾再帰で削除するのは無駄が多い気も.
もっといい書き方あるかな.
[追記]
ググったらもっといい書き方ありました.
プログラミングGauche 9.1 集合 練習問題 : Serendip - Webデザイン・プログラミング
(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
(define (loop lis)
(cond ((null? lis) '())
((cmp-fn elt (car lis)) (cdr lis))
((eq? (loop (cdr lis)) (cdr lis)) lis)
(else
(if (eq? (loop (cdr lis)) (cdr lis))
lis
(cons (car lis) (loop (cdr lis)))))))
(loop lis)))
eq?
で比較しろって書かれていたのはこういうことだったのか.
重複している部分があるのでif
の分岐を削除して書き換えます
(define (delete-1 elt lis . options)
(let-optionals* options ((cmp-fn equal?))
(define (loop lis)
(cond ((null? lis) '())
((cmp-fn elt (car lis)) (cdr lis))
((eq? (loop (cdr lis)) (cdr lis)) lis)
(else
(cons (car lis) (loop (cdr lis))))))
(loop lis)))
元のコードに一行足すだけだったとは・・・