发现一个网站,Projecteuler.net,上面可以做题。
其中第17道题是关于把1至一千的的数字转成英文单词的。写了一个程序可以完成这个功能,应该容易扩展为任意大的数字。程序写得挺复杂,肯定有简便方法。故意用不熟悉的Clojure语言写的,据说用函数式编程语言写程序想的时间比写的时间多,确实如此,应该是有效防止老年痴呆的方法。英文数字通常3个一组用逗号分隔,是有道理的,确实每三个是一个轮回。
;problem 17;
(def max-digit-num 4)
(def dict {
0 ""
1 "one"
2 "two"
3 "three"
4 "four"
5 "five"
6 "six"
7 "seven"
8 "eight"
9 "nine"
10 "ten"
11 "eleven"
12 "twelve"
13 "thirteen"
14 "fourteen"
15 "fifteen"
16 "sixteen"
17 "seventeen"
18 "eighteen"
19 "nineteen"
20 "twenty"
30 "thirty"
40 "forty"
50 "fifty"
60 "sixty"
70 "seventy"
80 "eighty"
90 "ninety"
})
(defn digit-seq [num]
(if (zero? num)
[]
(cons (rem num 10) (digit-seq (quot num 10)))))
(defn digit-seq-with-trailing-0 [num, len]
(let [ds (digit-seq num),
cur-len (count ds)
]
(if (>= cur-len len)
ds
(concat ds (repeat (- len cur-len) 0))
)
)
)
(defn digit-seq-with-index [num]
(reverse (map-indexed #( vector %1 %2 ) (digit-seq-with-trailing-0 num max-digit-num) )))
(defn sum-digit-seq-with-index [s]
(reduce #(+ (* %1 10) (second %2)) 0 s))
(defn digit2words [index,d, remain-sum]
(cond (= 0 d) ""
(= 0 index) (dict d)
(= 1 index) (if (= d 1)
(dict (+ (* 10 d) remain-sum))
(dict (* 10 d)))
(= 2 index) (if (= remain-sum 0)
(apply str (interpose " " [ (dict d) "hundred" ]))
(apply str (interpose " " [ (dict d) "hundred and" ])))
(= 3 index) (apply str (interpose " " [ (dict d) "thousand"]))
:else (dict d)
)
)
(defn num2words [num]
(let [digits (digit-seq-with-index num)]
(loop [ds digits, result ""]
(if (empty? ds)
result
(let [ [idx,digit] (first ds),
remain-seq (rest ds),
remain-num (sum-digit-seq-with-index remain-seq),
curr-result (digit2words idx digit remain-num),
former-plus-curr (apply str (interpose " " [result curr-result]))
]
(if (and (= idx 1) (= digit 1))
former-plus-curr
(recur remain-seq former-plus-curr))))
)
)
)
(defn count-non-blank-char [s]
(reduce #(+ %1 ( if (= %2 \space) 0 1)) 0 s))
(print (reduce + (map (comp count-non-blank-char num2words) (range 1 1001))) )
(print (map num2words (range 1 1001)))