Comparing each neighboring pairs in clojure vector - clojure

I'm learning Clojure. I found some exercises which require finding indexes for values in an array which are, for example, lower than next value. In Java I'd write
for (int i = 1; ...)
if (a[i-1] < a[i]) {result.add(i-1)}
in Clojure I found keep-indexed useful:
(defn with-keep-indexed [v]
(keep-indexed #(if (> %2 (get v %1)) %1) (rest v)))
It seems to works ok, but
is there a better way to do so?
This approach should work well for "find all values" or "find first value" (wrapped in first). But what if I need "find last". Then I have to either (with-keep-indexed (reverse v)) or (last (with-keep-indexed v)). Is there better way?
Edit: Example: for [1 1 2 2 1 2]
(with-keep-indexed [1 1 2 2 1 2])
;;=> (1 4)

Use partition to transform the vector to a sequence of consecutive pairs. Then use keep-indexed to add an index and filter them:
(defn indices< [xs]
(keep-indexed (fn [i ys]
(when (apply < ys) i))
(partition 2 1 xs)))
(indices< [1 1 2 2 1 2]) ;; => (1 4)
To find just the last such index, use last on this result. While it is possible to use reverse on the input, it does not offer any performance benefit for this problem.

The logic of forming pairs of numbers and comparing each number to the next number in the sequence can be factored out in a transducer that does not care about whether you want your result in the form of a vector with all indices or just the last index. Forming pairs can be done using partition as already suggested in the other answers, but I did not find a transducer implementation of that function, which would greatly facilitate. Here is a workaround that uses a mapping transducer along with some mutable state.
(defn indexed-pairs []
(let [s (atom [-2 nil nil])]
(comp (map #(swap! s (fn [[i a b]] [(inc i) b %])))
(remove (comp neg? first)))))
(defn indices-of-pairs-such-that [f]
(comp (indexed-pairs)
(filter (fn [[i a b]] (f a b)))
(map first)))
In this code, the function indices-of-pairs-such-that will return a transducer that we can use in various ways, for instance with into to produce a vector of indices:
(into [] (indices-of-pairs-such-that <) [1 1 2 2 1 2])
;; => [1 4]
Or, as was asked in the question, we can use tranduce along with a reducing function that always picks the second argument if we only want the last index:
(transduce (indices-of-pairs-such-that <) (completing (fn [a b] b)) nil [1 1 2 2 1 2])
;; => 4
This is the power of transducers: they decouple sequence algorithms from the results of those algorithms. The function indices-of-pairs-such-that encodes the sequence algorithm but does not have to know whether we want all the indices or just the last index.

The general problem can be solved with ...
(defn indexes-of-pairs [p coll]
(let [check-list (map (fn [i x rx] (when (p x rx) i)) (range) coll (rest coll))]
(filter identity check-list)))
... which returns the indexes of adjacent pairs of a sequence coll that are related by predicate p. For example,
(indexes-of-pairs < [1 1 2 2 1 2])
=> (1 4)
For your example, you can define
(def with-keep-indexed (partial indexes-of-pairs <))
Then
(with-keep-indexed [1 1 2 2 1 2])
=> (1 4)

There are many ways to solve a problem. Here are two alternatives, including a unit test using my favorite template project. The first one uses a loop over the first (N-1) indexes in an imperative style not so different than what you'd write in Java:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn step-up-index-loopy
[xs] ; a sequence of "x" values
(let-spy
[xs (vec xs) ; coerce to vector in case we get a list (faster)
accum (atom []) ; an accumulator
N (count xs)]
(dotimes [i (dec N)] ; loop starting at i=0
(let-spy [j (inc i)
ival (get xs i)
jval (get xs j)]
(when (< ival jval)
(swap! accum conj i))))
#accum))
When run, it produces this output:
calling step-up-index-loopy
xs => [1 1 2 2 1 2]
accum => #object[clojure.lang.Atom 0x4e4dcf7c {:status :ready, :val []}]
N => 6
j => 1
ival => 1
jval => 1
j => 2
ival => 1
jval => 2
j => 3
ival => 2
jval => 2
j => 4
ival => 2
jval => 1
j => 5
ival => 1
jval => 2
The second one uses a more "functional" style that avoids direct indexing. Sometimes this makes things simpler, but sometimes it can appear more complicated. You be the judge:
(defn step-up-index
[xs] ; a sequence of "x" values
(let-spy-pretty
[pairs (partition 2 1 xs)
pairs-indexed (indexed pairs) ; append index # [0 1 2 ...] to beginning of each pair
reducer-fn (fn [accum pair-indexed]
; destructure `pair-indexed`
(let-spy [[idx [ival jval]] pair-indexed]
(if (< ival jval)
(conj accum idx)
accum)))
result (reduce reducer-fn
[] ; initial state for `accum`
pairs-indexed)]
result))
The function indexed is from the Tupelo Clojure library.
When you run the code you'll see:
calling step-up-index
pairs =>
((1 1) (1 2) (2 2) (2 1) (1 2))
pairs-indexed =>
([0 (1 1)] [1 (1 2)] [2 (2 2)] [3 (2 1)] [4 (1 2)])
reducer-fn =>
#object[tst.demo.core$step_up_index$reducer_fn__21389 0x108aaf1f "tst.demo.core$step_up_index$reducer_fn__21389#108aaf1f"]
[idx [ival jval]] => [0 [1 1]]
[idx [ival jval]] => [1 [1 2]]
[idx [ival jval]] => [2 [2 2]]
[idx [ival jval]] => [3 [2 1]]
[idx [ival jval]] => [4 [1 2]]
result =>
[1 4]
Both of them work:
(dotest
(newline)
(println "calling step-up-index-loopy")
(is= [1 4]
(step-up-index-loopy [1 1 2 2 1 2]))
(newline)
(println "calling step-up-index")
(is= [1 4]
(step-up-index [1 1 2 2 1 2])))
With results:
-----------------------------------
Clojure 1.10.3 Java 15.0.2
-----------------------------------
Testing tst.demo.core
Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
The form let-spy is from the Tupelo Clojure library, and makes writing & debugging things easier. See the docs for more info. When satisfied everything is working, replace with
let-spy => let
Also be sure to study the list of documentation sources included in the template project, especially the Clojure CheatSheet.
Another solution using keep-indexed is pretty short:
(defn step-up-index
[xs]
(let [pairs (partition 2 1 xs)
result (vec
(keep-indexed
(fn [idx pair]
(let [[ival jval] pair]
(when (< ival jval)
idx)))
pairs))]
result))
(dotest
(is= [1 4] (step-up-index [1 1 2 2 1 2])))

Related

Concatenate elements to list by using loop in clojure?

I am trying to get into Lisps and FP by trying out the 99 problems.
Here is the problem statement (Problem 15)
Replicate the elements of a list a given number of times.
I have come up with the following code which simply returns an empty list []
I am unable to figure out why my code doesn't work and would really appreciate some help.
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(loop [x 0]
(when (< x n)
(conj returnList head)
(recur (inc x))))
(recur rest returnList)))))
(defn -main
"Main" []
(test/is (=
(replicateList [1 2] 2)
[1 1 2 2])
"Failed basic test")
)
copying my comment to answer:
this line: (conj returnList head) doesn't modify returnlist, rather it just drops the result in your case. You should restructure your program to pass the accumulated list further to the next iteration. But there are better ways to do this in clojure. Like (defn replicate-list [data times] (apply concat (repeat times data)))
If you still need the loop/recur version for educational reasons, i would go with this:
(defn replicate-list [data times]
(loop [[h & t :as input] data times times result []]
(if-not (pos? times)
result
(if (empty? input)
(recur data (dec times) result)
(recur t times (conj result h))))))
user> (replicate-list [1 2 3] 3)
;;=> [1 2 3 1 2 3 1 2 3]
user> (replicate-list [ ] 2)
;;=> []
user> (replicate-list [1 2 3] -1)
;;=> []
update
based on the clarified question, the simplest way to do this is
(defn replicate-list [data times]
(mapcat (partial repeat times) data))
user> (replicate-list [1 2 3] 3)
;;=> (1 1 1 2 2 2 3 3 3)
and the loop/recur variant:
(defn replicate-list [data times]
(loop [[h & t :as data] data n 0 res []]
(cond (empty? data) res
(>= n times) (recur t 0 res)
:else (recur data (inc n) (conj res h)))))
user> (replicate-list [1 2 3] 3)
;;=> [1 1 1 2 2 2 3 3 3]
user> (replicate-list [1 2 3] 0)
;;=> []
user> (replicate-list [] 10)
;;=> []
Here is a version based on the original post, with minimal modifications:
;; Based on the original version posted
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(recur
rest
(loop [inner-returnList returnList
x 0]
(if (< x n)
(recur (conj inner-returnList head) (inc x))
inner-returnList)))))))
Please keep in mind that Clojure is mainly a functional language, meaning that most functions produce their results as a new return value instead of updating in place. So, as pointed out in the comment, the line (conj returnList head) will not have an effect, because it's return value is ignored.
The above version works, but does not really take advantage of Clojure's sequence processing facilities. So here are two other suggestions for solving your problem:
;; Using lazy seqs and reduce
(defn replicateList2 [l n]
(reduce into [] (map #(take n (repeat %)) l)))
;; Yet another way using transducers
(defn replicateList3 [l n]
(transduce
(comp (map #(take n (repeat %)))
cat
)
conj
[]
l))
One thing is not clear about your question though: From your implementation, it looks like you want to create a new list where each element is repeated n times, e.g.
playground.replicate> (replicateList [1 2 3] 4)
[1 1 1 1 2 2 2 2 3 3 3 3]
But if you would instead like this result
playground.replicate> (replicateList [1 2 3] 4)
[1 2 3 1 2 3 1 2 3 1 2 3]
the answer to your question will be different.
If you want to learn idiomatic Clojure you should try to find a solution without such low level facilities as loop. Rather try to combine higher level functions like take, repeat, repeatedly. If you're feeling adventurous you might throw in laziness as well. Clojure's sequences are lazy, that is they get evaluated only when needed.
One example I came up with would be
(defn repeat-list-items [l n]
(lazy-seq
(when-let [s (seq l)]
(concat (repeat n (first l))
(repeat-list-items (next l) n)))))
Please also note the common naming with kebab-case
This seems to do what you want pretty well and works for an unlimited input (see the call (range) below), too:
experi.core> (def l [:a :b :c])
#'experi.core/
experi.core> (repeat-list-items l 2)
(:a :a :b :b :c :c)
experi.core> (repeat-list-items l 0)
()
experi.core> (repeat-list-items l 1)
(:a :b :c)
experi.core> (take 10 (drop 10000 (repeat-list-items (range) 4)))
(2500 2500 2500 2500 2501 2501 2501 2501 2502 2502)

How do I create a function that inserts an element between each pair of elements in a vector

I want to write a function that inserts elements between existing elements in a vector. The inserted elements are a function of the elements that precede and succeed it, with the first and last elements remaining unaffected.
E.g. I want inserted elements to be the mean of the elements that precede and succeed it:
Input:
[1 10 15]
Output:
[1 5.5 10 12.5 15]
What is the best way to do this in Clojure?
Here's another way:
(defn insert-mean-between [xs]
(let [f (fn [x y]
[(* (+ x y) 0.5) y])]
(->> xs
(partition 2 1)
(mapcat (partial apply f))
(cons (first xs))
vec)))
(insert-mean-between [1 10 15])
;;=> [1 5.5 10 12.5 15]
The main trick is that f is returning the answer and the RHS input. This way later on they will all compose together without repeats. The only problem you will have is that the first element is missing. So we just cons it onto the front. From the outset we had to know that cons would be a convenient operation when we chose to be returning the RHS rather than the LHS.
As calculating the mean was just an example, an improved solution would be for the inserting to be independent of the mean/whatever function:
(defn calc-mean [x y] (* (+ x y) 0.5)
(insert-between calc-mean [1 10 15])
Then a more general inserting function might be:
(defn insert-between [g xs]
(->> xs
(partition 2 1)
(mapcat (fn [[x y]] [(g x y) y]))
(cons (first xs))))
and the list of variants won't be complete without the recursive lazy sequence generation:
(defn with-avg [[x1 & [x2 :as tail] :as items]]
(when (seq items)
(if (seq tail)
(lazy-cat [x1 (/ (+ x1 x2) 2)] (with-avg tail))
[x1])))
user> (with-avg [1 2 3 4 5])
;;=> (1 3/2 2 5/2 3 7/2 4 9/2 5)
user> (with-avg [1])
;;=> [1]
user> (with-avg [])
;;=> nil
user> (with-avg [1 2])
;;=> (1 3/2 2)
user> (with-avg [1 2 3])
;;=>(1 3/2 2 5/2 3)
One way I could solve it is pattern matching Vector as f s t, I'm assuming it has 3 elements
Then create variable to assign first median first + second / 2 and second median second + third /2.
At the end return a new Vector with a combination you want.
Example, (I'm using lein REPL)
user=> (defn insert_medians[vect]
#_=> (let [[f s t] vect
#_=> m1 (float (/ (+ f s) 2))
#_=> m2 (float (/ (+ s t) 2))]
#_=> [f m1 s m2 t]))
#'user/insert_medians
user=> (insert_medians [1 10 15])
[1 5.5 10 12.5 15]
If a vector is larger than 3 elems, you need to find all the medians first and then insert into the original vector using interleave fn.
(defn insert-between
"Inserts elements between existing elements in a vector v. The inserted
elements are a result of applying the function f to the elements that precede
and succeed it, with the first and last elements of v remaining unaffected."
[f [x & xs :as v]]
(->> (partition 2 1 v)
(mapcat (fn [[a b]] [(f a b) b]))
(cons x)
(into [])))
(defn mean [& numbers]
(float (/ (apply + numbers) (count numbers))))
(insert-between mean [1 10 15]) ; => [1 5.5 10 10 12.5 15]
(insert-between + [1 10 15 20 25]) ; => [1 11 10 25 15 35 20 45 25]
(insert-between mean []) ; => [nil] :(

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.

In clojure, how to build lazy sequence using iterate function

The clojure document gives the following examples:
(take 10 (iterate (partial + 2) 0))
(def powers-of-two (iterate (partial * 2) 1))
(take 10 powers-of-two)
(def fib (map first (iterate (fn [[a b]] [b (+ a b)]) [1 1])))
(take 10 fib)
Anyone can explain the syntax of clojure's iterate function in more detail? I am very confused with all the usage. Why two brackets are there in (fn [[a b]] [b (+ a b)])?
Another example can be found here:
(defn iter [[x y]]
(vector y (+ x y)))
(nth (iterate iter [0 1]) 10000)
iterate takes a function f and an initial value x and produces a lazy sequence. The first element in the seq is x. Each subsequent element is computed by calling f with the previous element.
Example 1:
(iterate (partial + 2) 0)
This generates a sequence, starting at 0, where each element is the previous element with 2 added to it. I.e.:
0
(+ 2 0) ; => 2
(+ 2 2) ; => 4
(+ 2 4) ; => 6
; etc
Each element in the seq is passed to (partial + 2) when generating the following element.
Example 2:
(iterate (partial * 2) 1)
This generates a sequence, starting at 1, where each element is the previous element multiplied by 2. I.e.:
1
(* 2 1) ; => 2
(* 2 2) ; => 4
(* 2 4) ; => 8
(* 2 8) ; => 16
; etc
Again, you can see how each element feeds into the generation of the next one.
Example 3:
(iterate (fn [[a b]] [b (+ a b)]) [1 1])
Firstly, (fn [[a b]] ...) is a way to destructure a value into parts. In this case, the function accepts a two-element vector and unpacks it into the local variables a and b.
The function returns a two-element vector containing b and the sum of a and b (i.e. the second value in the previous pair and the sum of both values in the previous pair).
With this in mind, this iterate call generates:
[1 1]
[1 (+ 1 1)] ; => [1 2]
[2 (+ 1 2)] ; => [2 3]
[3 (+ 2 3)] ; => [3 5]
[5 (+ 3 5)] ; => [5 8]
; etc
Then (map first ...) grabs the first value in each pair, which gives you your Fibonacci sequence.

How to remove multiple items from a list?

I have a list [2 3 5] which I want to use to remove items from another list like [1 2 3 4 5], so that I get [1 4].
thanks
Try this:
(let [a [1 2 3 4 5]
b [2 3 5]]
(remove (set b) a))
which returns (1 4).
The remove function, by the way, takes a predicate and a collection, and returns a sequence of the elements that don't satisfy the predicate (a set, in this example).
user=> (use 'clojure.set)
nil
user=> (difference (set [1 2 3 4 5]) (set [2 3 5]))
#{1 4}
Reference:
http://clojure.org/data_structures#toc22
http://clojure.org/api#difference
You can do this yourself with something like:
(def a [2 3 5])
(def b [1 2 3 4 5])
(defn seq-contains?
[coll target] (some #(= target %) coll))
(filter #(not (seq-contains? a %)) b)
; (3 4 5)
A version based on the reducers library could be:
(require '[clojure.core.reducers :as r])
(defn seq-contains?
[coll target]
(some #(= target %) coll))
(defn my-remove
"remove values from seq b that are present in seq a"
[a b]
(into [] (r/filter #(not (seq-contains? b %)) a)))
(my-remove [1 2 3 4 5] [2 3 5] )
; [1 4]
EDIT Added seq-contains? code
Here is my take without using sets;
(defn my-diff-func [X Y]
(reduce #(remove (fn [x] (= x %2)) %1) X Y ))