4clojureで出くわした。
"1101"
のような2進数を表す文字列を10進数に変換する関数を書け。
自分の解答はこれ。
(fn [s] (->> (reverse s) (map-indexed (fn [idx item] [idx item])) (reduce (fn [sum v] (+ sum (* (- (int (v 1)) 48) (int (Math/pow 2 (v 0)))))) 0)))
めっちゃ長い。
- 1桁目から順に処理したいからまず
reverse
。 map-indexd
で各桁に0から始まる連番を振る。例えば1101
->([0 \1] [1 \1] [2 \0] [3 \1])
。reduce
で各桁の値(0or1)に、「さっき振った連番のべき乗」をかける。
という感じ。(- (int (v 1)) 48)
はchar
型の各桁を\0
の文字コード番号である48を引くことでint
に変換してる*1。本題じゃないのでスルーでもOK。
見かけた解答ですこぶるエレガントなんだけど意味が分からなかったのがこれ。*2
(fn [bi-str] reduce #(+ (* 2 %1) (- (int %2) 48)) 0 bi-str)
各桁の10進数値を合計しながら桁が進む毎に2倍2倍していけば良い、ということ。分かってみると、なんか基本的なことのようにも見える。きっと学校できちんと数学や情報学んだ人達には初歩的なことなんだろうなーって気がする。 自分の解答のように、各桁が10進数でいくつなのかを各桁ごとに計算して足し上げるよりはるかにシンプル。。
4clojureをやってると、自分がいかに駄目か思い知らされて辛い。followしてる数人の中に、驚異的にエレガントな解答がほぼ毎回あって、感動&へこむ。
ちなみにfollowしてる人の解答で、上記以上にゴルフィーでシンプルなのが、これ。
#(Integer/parseInt % 2)
確かに(笑)。勉強になる!