How to convert a Hex string to a Decimal number in Clojure

The best way to learn any new programming language is to practice.

This applies especially to such a beautiful functional-programming language like Clojure with thousands of functions.

Today I created my own super basic “Hex to Decimal Converter”, and it’s definitely not the most elegant nor performant way to do it in Clojure. Normally you would probably do some bitshifting, utilizing Java functions and string formatting.

But it works and I learned about a new function called map-indexed, which came handy in the for - list comprehension as the use of an atom was an overkill for the trivial need of an incrementing index counter.


Decimal vs Hexadecimal

Decimal is base 10 and uses 10 distinct characters to count.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

Hexadecimal is base 16 and uses 16 distinct characters to count.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, plus the letters A, B, C, D, E, F.

Decimal to Hexadecimal Conversion Table

Decimal0123456789101112131415
Hexadecimal0123456789ABCDEF

How to convert from Hex to Decimal

Let’s take the hex number AF7B5 . It is made up of A, F, 7, B, 5.

We start from right with 5 and go backwards.

5 x (16^0) =  5 x (1)                 =  5 x 1     =      5
B x (16^1) = 11 x (16)                = 11 x    16 =    176
7 x (16^2) =  7 x (16 x 16)           =  7 x   256 =   1792
F x (16^3) = 15 x (16 x 16 x 16)      = 15 x  4096 =  61440
A x (16^4) = 10 x (16 x 16 x 16 x 16) = 10 x 65536 = 655360
============================================================
Total                                                718773

Summarize the results

5 + 176 + 1792 + 61440 + 655360 = 718773

So the decimal equivalent of AF7B5 is 718773.

Clojure Algorithm

(def hex-value {:0 0
                :1 1
                :2 2
                :3 3
                :4 4
                :5 5
                :6 6
                :7 7
                :8 8
                :9 9
                :a 10
                :b 11
                :c 12
                :d 13
                :e 14
                :f 15})

(defn hex-to-reverse-keyword-vector
  "Convert a hex string to a reverse keyword vector"
  [hex]
  (->> (str/lower-case hex)
       reverse
       (map str)
       (map keyword)
       vec))

;; user=> (hex-to-reverse-keyword-vector "ABCDEF")
;; [:f :e :d :c :b :a]

;; user=> (map-indexed vector (hex-to-reverse-keyword-vector "ABCDEF"))
;; ([0 :f] [1 :e] [2 :d] [3 :c] [4 :b] [5 :a])

(defn hex-to-decimal
  "Calculate the decimal value of a given hex-string"
  [hex]
  (->> (for [x (map-indexed vector (hex-to-reverse-keyword-vector hex))]
           (->> (* ((second x) hex-value)
                   (Math/pow 16 (first x)))))
       (reduce +)))

;; user=> (hex-to-decimal "5B3E")
;; 23358.0