(-> % read write unlearn)

My writings on this area are my own delusion

clojure 2進->10進変換

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. 1桁目から順に処理したいからまずreverse
  2. map-indexdで各桁に0から始まる連番を振る。例えば1101 -> ([0 \1] [1 \1] [2 \0] [3 \1])
  3. 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)

確かに(笑)。勉強になる!

*1:このやり方も4clojureで先達の解答から学んだ

*2:説明しやすくするため、形式を揃えるため、一部改変しています。