Problem 17 - 数字を数えると

面倒な問題が残っていたので片付ける。

Problem 17 - PukiWiki

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なら楽ちん。


メモリにやさしいのでかなり活躍の予感。