clojure - Read list of numbers by place value? (ClojureScript tricks)


Keywords:clojure 


Question: 

I was wondering today if i have a list of numbers. Is there a function in ClojureScript which returns a number made from the numbers by place value? (I dont mean a list(), but just some numbers)

For e.g.:

I have a some numbers 1, 2, 3, and i am looking for a function which converts it to 123 (one hundred and twenty-three).

I thought I found a solution for this with read-string

(read-string (str 1 2 3))
;=> 123

but sadly it not works well if i want to use it in the function discussed below.

I have a "functionmade" map where keys are vectors and values are numbers. Like this: {[0 0] 0, [0 1] 1, ... [4 5] 45, ... [9 9] 99}

The only way i can use get function on this map is:

(get {[0 2] 2} [0 2])
;=> 2
; or
(get {[4 5] 45} [4 5])
;=> 45

This is grinding, but it works. To make it look much better i tried to define a function where i used read-string: (read/ refers to cljs.reader)

(defn get-oxo [x y]
  (get {[x y] (read/read-string (str x y))} [x y]))
;So i can use it like this for e.g.:
(get-oxo 4 5)
;=> 45

It also returns values which are not in the map:

(get-oxo 112 358)
;=> 112358

I suppose the problem is that this way get-oxo returns not the value of the paired key, but the number constructed from x y...

So the questions is how can I fix it to return the value of the paired key and not the number constructed from the numbers i give to the functions?

(There is another problem if i want to generate a map with wider range of numbers, for e.g. not just 0-9 but 0-99. This way the algorythm of get-oxo is not true. I use the function discussed at: ClojureScript zipmap tricks me or what?).


2 Answers: 

the problem is you get what you put:

just decompose your function to see it clearly:

(defn get-oxo [x y]
  (let [new-map {[x y] (read/read-string (str x y))}]
    (println new-map)
    (get new-map [x y])))
#'user/get-oxo

user> (get-oxo 100 200)
;;=> {[100 200] 100200}
;;=> 100200

So you generate your map inside the function, and get it's key and you get... a totally valid behavior

to get something from your map , you need to have your map as the first argument of get function

(defn get-oxo [input x y]
  (get input [x y]))
#'user/get-oxo

user> (def data {[0 0] 0 [0 1] 1 [0 2] 2})
#'user/data

user> (get-oxo data 0 1)
1

user> (get-oxo data 2 3)
nil

then, if you need the key (i mean pair from map) instead of value, you can modify it this way, using find function instead of get:

(defn get-oxo [input x y]
  (first (find input [x y])))
#'user/get-oxo

user> (get-oxo data 0 1)
[0 1]

user> (get-oxo data 2 3)
nil

also writing and reading string to get a number looks redundant. You can easily make a simple function for that:

(defn digits->num [digits]
  (reduce (fn [acc d] (+ (* 10 acc) d))
          0
          digits))
#'user/digits->num

user> (digits->num [0])
0

user> (digits->num [])
0

user> (digits->num [1])
1

user> (digits->num [1 2 3 4])
1234

user> (digits->num [0 0 1 0])
10
 

You can simply apply str function to your sequence of digits:

(apply str '(1 2 3))
;; => "123"