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

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?).

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"

Related

Juxtaposed transducers

Let's imagine we want to compute two different functions on some given input. How can we do that with transducers?
For example, let's say we have these two transducers:
(def xf-dupl (map #(* 2 %)))
(def xf-inc (map inc))
Now, I would like some function f that takes a collection of transducers and returns a new transducer that combines them, as follows:
(into [] (f [xf-dupl xf-inc]) (range 5))
; => [[0 2 4 6 8] [1 2 3 4 5]]
There should probably be a very simple solution to this, but I cannot find it.
Note: I have tried with cgrand/xforms library's transjuxt, but there I get the following
(into [] (x/transjuxt {:a xf-dupl :b xf-inc}) (range 5))
; => [{:a 0 :b 1}]
Thanks for your help!
Using cgrand/xforms you can define f as
(defn f
[xfs]
(comp
(x/multiplex (zipmap (range) xfs))
(x/by-key (x/into []))
(map second)))
Calling f as you outlined in your question yields
user> (into [] (f [xf-dupl xf-inc]) (range 5))
[[0 2 4 6 8] [1 2 3 4 5]]

Why am I getting a StackoverflowError on a function without explicit recursion

I am trying to generate a relatively small (1296 elements) list of vectors essentially enumerating 4 base 6 digits from [0 0 0 0] to [5 5 5 5]
[0 0 0 0], [1 0 0 0] ... [5 0 0 0], [0 1 0 0] ... [5 5 5 5]
Currently what I have is:
(letfn [(next-v [v]
(let [active-index (some (fn [[i e]] (when (> 5 e) i))
(map-indexed vector v))]
(map-indexed #(cond
(> active-index %1) 0
(= active-index %1) (inc %2)
:else %2)
v)))]
(last (take 1290 (iterate next-v [0 0 0 0]))))
This works but it eventually blows the stack.
What am I doing here that causes the StackOverflowError?
How can I structure my code so that it is "safe"?
Is there a better way of doing what I am trying to do?
The way I would solve this is:
(def my-range
(for [i (range 0 6)
j (range 0 6)
x (range 0 6)
y (range 0 6)]
[i j x y]))
(nth my-range 1295) ;;=> [5 5 5 5]
Generalized:
(defn combine [coll]
(for [i (range 6)
j coll]
(conj j i)))
(combine (map list (range 6)))
(combine (combine (map list (range 6))))
(combine (combine (combine (map list (range 6)))))
(def result (nth (iterate combine (map list (range 6))) 3))
This is due to lazyiness in the iterated function body. Notice that the result returned by the first call of next-v is passed to next-v again, before being evaluated (because its a lazy seq), then next-v returns again an unevaluated lazy-seq which will again be passed to it.
When you realize the final lazy seq, to produce the first element all the chained seqs have to be realized to get through to your initial [0 0 0 0]. This will blow the stack.
Stuart Sierra wrote a nice article on this with more examples: http://stuartsierra.com/2015/04/26/clojure-donts-concat
You could simply wrap the map-indexed call in the let body in a vec.
Finding a more generic algorithm to your problem is recommended though.

How do I replicate items from a list in Clojure?

I've tried this for so many nights that I've finally given up on myself. Seems like an extremely simple problem, but I guess I'm just not fully understanding Clojure as well as I should be (I partially attribute that to my almost sole experience with imperative languages). The problem is from hackerrank.com
Here is the problem:
Problem Statement
Given a list repeat each element of the list n times. The input and output
portions will be handled automatically by the grader.
Input Format
First line has integer S where S is the number of times you need to repeat
elements. After this there are X lines, each containing an integer. These are the
X elements of the array.
Output Format
Repeat each element of the original list S times. So you have to return
list/vector/array of S*X integers. The relative positions of the values should be
same as the original list provided as input.
Constraints
0<=X<=10
1<=S<=100
So, given:
2
1
2
3
Output:
1
1
2
2
3
3
I've tried:
(fn list-replicate [num list]
(println (reduce
(fn [element seq] (dotimes [n num] (conj seq element)))
[]
list))
)
But that just gives me an exception. I've tried so many other solutions, and this probably isn't one of my better ones, but it was the quickest one I could come up with to post something here.
(defn list-replicate [num list]
(mapcat (partial repeat num) list))
(doseq [x (list-replicate 2 [1 2 3])]
(println x))
;; output:
1
1
2
2
3
3
The previous answer is short and it works, but it is very "compressed" and is not easy for new people to learn. I would do it in a simpler and more obvious way.
First, look at the repeat function:
user=> (doc repeat)
-------------------------
clojure.core/repeat
([x] [n x])
Returns a lazy (infinite!, or length n if supplied) sequence of xs.
user=> (repeat 3 5)
(5 5 5)
So we see how to easily repeat something N times.
What if we run (repeat n ...) on each element of the list?
(def N 2)
(def xvals [1 2 3] )
(for [curr-x xvals]
(repeat N curr-x))
;=> ((1 1) (2 2) (3 3))
So we are getting close, but we have a list-of-lists for output. How to fix? The simplest way is to just use the flatten function:
(flatten
(for [curr-x xvals]
(repeat N curr-x)))
;=> (1 1 2 2 3 3)
Note that both repeat and for are lazy functions, which I prefer to avoid unless I really need them. Also, I usually prefer to store my linear collections in a concrete vector, instead of a generic "seq" type. For these reasons, I include an extra step of forcing the results into a single (eagar) vector for the final product:
(defn list-replicate [num-rep orig-list]
(into []
(flatten
(for [curr-elem xvals]
(repeat N curr-elem)))))
(list-replicate N xvals)
;=> [1 1 2 2 3 3]
I would suggest building onto Alan's solution and instead of flatten use concat as this will preserve the structure of the data in case you have input sth like this [[1 2] [3 4]].
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => ([1 2] [1 2] [3 4] [3 4])
unlike with flatten, which does the following
((fn [coll] (flatten (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => (1 2 1 2 3 4 3 4)
as for simple lists e.g. '(1 2 3), it works the same:
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) '(1 2 3))
output => (1 1 2 2 3 3)
(reduce #(count (map println (repeat %1 %2))) num list)

How to create a map from a list of key-value pairs using values as a predicate in Clojure?

Just started learning Clojure, so I imagine my main issue is I don't know how to formulate the problem correctly to find an existing solution. I have a map:
{[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}
and I'd like to "transform" it to:
{[0 1] "a", [1 1] "a"}
i.e. use the two first elements of the composite key as they new key and the third element as the value for the key-value pair that had the highest value in the original map.
I can easily create a new map structure:
=> (into {} (for [[[x y z] v] {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}] [[x y] {z v}]))
{[0 1] {"b" 1}, [1 1] {"a" 1}}
but into accepts no predicates so last one wins. I also experimented with :let and merge-with but can't seem to correctly refer to the map, eliminate the unwanted pairs or replace values of the map while processing.
You can do this by threading together a series of sequence transformations.
(->> data
(group-by #(->> % key (take 2)))
vals
(map (comp first first (partial sort-by (comp - val))))
(map (juxt #(subvec % 0 2) #(% 2)))
(into {}))
;{[0 1] "a", [1 1] "a"}
... where
(def data {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
You build up the solution line by line. I recommend you follow in the footsteps of the construction, starting with ...
(->> data
(group-by #(->> % key (take 2)))
;{(0 1) [[[0 1 "a"] 2] [[0 1 "b"] 1]], (1 1) [[[1 1 "a"] 1]]}
Stacking up layers of (lazy) sequences can run fairly slowly, but the transducers available in Clojure 1.7 will allow you to write faster code in this idiom, as seen in this excellent answer.
Into tends to be most useful when you just need to take a seq of values and with no additional transformation construct a result from it using only conj. Anything else where you are performing construction tends to be better suited by preprocessing such as sorting, or by a reduction which allows you to perform accumulator introspection such as you want here.
First of all we have to be able to compare two strings..
(defn greater? [^String a ^String b]
(> (.compareTo a b) 0))
Now we can write a transformation that compares the current value in the accumulator to the "next" value and keeps the maximum. -> used somewhat gratuitusly to make the update function more readable.
(defn transform [input]
(-> (fn [acc [[x y z] _]] ;; take the acc, [k, v], destructure k discard v
(let [key [x y]] ;; construct key into accumulator
(if-let [v (acc key)] ;; if the key is set
(if (greater? z v) ;; and z (the new val) is greater
(assoc acc key z) ;; then update
acc) ;; else do nothing
(assoc acc key z)))) ;; else update
(reduce {} input))) ;; do that over all [k, v]s from empty acc
user> (def m {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
#'user/m
user> (->> m
keys
sort
reverse
(mapcat (fn [x]
(vector (-> x butlast vec)
(last x))))
(apply sorted-map))
;=> {[0 1] "a", [1 1] "a"}

How can I find the index of the smallest member of this vector in Clojure?

I have used the following expression to retrieve the index of the smallest number in a vector. However, I would like to avoid the use of .indexOf (for efficiency reasons and maybe numeric precision, although I guess the numbers are implicitly converted to strings).
(.indexOf [1 2 3 4 0 5]
(reduce #(if (< %1 %2) %1 %2) [1 2 3 4 0 5] ))
Would it be possible to do it differently using reduce?
user=> (first (apply min-key second (map-indexed vector [1 2 4 0 5])))
3
I'd suggest using loop/recur if you want to do this efficiently, perhaps something like the following:
(defn min-index [v]
(let [length (count v)]
(loop [minimum (v 0)
min-index 0
i 1]
(if (< i length)
(let [value (v i)]
(if (< value minimum)
(recur value i (inc i))
(recur minimum min-index (inc i))))
min-index))))
The idea is to iterate across the whole vector, keeping track of the minimum and the index of the minimum value found so far at each point.
You can also use reduce:
(def v [1 2 3 4 0 5])
(second (reduce (fn [[curr-min min-idx curr-idx] val]
(if (< val curr-min)
[val curr-idx (inc curr-idx)]
[curr-min min-idx (inc curr-idx)])) [(first v) 0 0] v)) ;; => 4
The result of reduce is actually a three-element vector consisting of the minimum value, its index, and an index tracker (which is not important), respectively. And it traverses the collection once.
The initial value provided to reduce is basically the first element of the collection.
I know the question is old, but it is here for posterity's sake.
Following up on #Alex Taggart's answer, using thread-last macro:
user=> (->> [1 2 4 0 5]
(map-indexed vector) ; [[0 1] [1 2] [2 4] [3 0] [4 5]]
(apply min-key second) ; [3 0]
first)
3