Problem 17 - 数字を数えると
面倒な問題が残っていたので片付ける。
1 から 5 までの数字を英単語で書けば one, two, three, four, five であり、全部で 3 + 3 + 4 + 4 + 5 = 19 の文字が使われている。
では 1 から 1000 (one thousand) までの数字をすべて英単語で書けば、全部で何文字になるか。
注: 空白文字やハイフンを数えないこと。例えば、342 (three hundred and forty-two) は 23 文字、115 (one hundred and fifteen) は20文字と数える。なお、"and" を使用するのは英国の慣習。
面倒過ぎる。
(define (number->string-list n) (cond ((zero? n) '()) ((< n 10) (list (list-ref '("one" "two" "three" "four" "five" "six" "seven" "egiht" "nine") (- n 1)))) ((< n 20) (list (list-ref '("ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen") (- n 10)))) ((< n 100) (cons (list-ref '("twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety") (- (quotient n 10) 2)) (number->string-list (modulo n 10)))) ((< n 1000) (append (number->string-list (quotient n 100)) (cons "hundred" (let ((res (number->string-list (modulo n 100)))) (if (null? res) res (cons "and" res)))))) ((< n 10000) (append (number->string-list (quotient n 1000)) (cons "thousand" (number->string-list (modulo n 1000))))))) (define (map-sum f l) (fold (lambda (x acc) (+ (f x) acc)) 0 l)) (map-sum (lambda (n) (map-sum string-length (number->string-list n))) (iota 1000 1)) ; 21124
同じ事をやっているようで微妙に中身が異なる。こういう面倒なのがすっきり書けるようになりたいんだよなぁ。
(apply + (map ...))とすることが多いので、map-sumという新たなユーティリティを作ってみた。
foldとmapでは引数の数が違うので書き換えが面倒だけど、map-sumなら楽ちん。
メモリにやさしいのでかなり活躍の予感。