((fn [coll] (letfn [(add-item [acc coll idx]
(conj acc (nth coll idx)))
(add-group [acc coll]
(conj acc (create-group coll)))
(decrease-coll [coll acc]
(drop (count (last acc)) coll))
(not-group-member? [idx coll]
(not= (first coll) (nth coll idx)))
(out-of-bounds? [idx coll]
(or (empty? coll) (> idx (count coll))))
(create-group [coll] (loop [idx 0
coll coll
acc []]
(if (or (out-of-bounds? idx coll)
(not-group-member? idx coll))
acc
(recur (inc idx) coll (add-item acc coll idx)))))
(process-coll [coll] (loop [coll coll
acc []]
(if (empty? coll)
acc
(recur (decrease-coll coll acc)
(add-group acc coll)))))]
(process-coll coll))) [1 1 2 1 1 1])
When I try to run this I receive
java.lang.IndexOutOfBoundsException: null
RT.java:795 clojure.lang.RT.nthFrom
RT.java:764 clojure.lang.RT.nth
/clojure/scratch-work-4clojure.clj:13 user/eval10378[fn]
/clojure/scratch-work-4clojure.clj:22 user/eval10378[fn]
/clojure/scratch-work-4clojure.clj:7 user/eval10378[fn]
/clojure/scratch-work-4clojure.clj:30 user/eval10378[fn]
/clojure/scratch-work-4clojure.clj:31 user/eval10378[fn]
/clojure/scratch-work-4clojure.clj:3 user/eval10378
I've been trying to debug this for some time now. I broke it into several functions to try to track down what's causing the error but haven't been able to determine it yet. Any help on what's causing this and how to debug such errors in Clojure in the future would be appreciated.
Your out-of-bounds? check is wrong. You want >= instead of >. Indexes go from 0 to n-1.
Related
I'm trying to make a take function myself, but this appears to be giving a stack overflow, any idea what may be causing it?
(defn my-take-plus [n Lst LstAcc count]
(let [LstVec (into [] Lst)]
(cond (= count n) LstAcc
:else
(do
(conj LstAcc (first LstVec))
(inc count)
(my-take-plus n (apply list(rest LstVec)) LstAcc count)
)
)
)
)
(defn my-take [n Lst]
(my-take-plus n Lst [] 0)
)
also, there is one more 'clojurish' way to do this:
(defn my-take [n data]
(when (and (pos? n) (seq data))
(lazy-seq
(cons (first data)
(my-take (dec n) (rest data))))))
this one is lazy, and also prevents stack overflow.. Moreover, as far as i remember, the clojure.core/take is implemented in a similar way
I would consider using a loop/recur strategy so that Clojure does tail-call optimization (TCO) to prevent a Stack Overflow.
(defn take' [n coll]
(loop [n n
acc []
coll coll]
(cond
(empty? coll) acc
((comp not pos?) n) acc
:else (recur (dec n) (conj acc (first coll)) (rest coll)))))
In your example, I would've considered using an if since you only had to conditional branches. cond is generally used more like a case statement.
I am trying to complete the Hackerrank Maximum Element challenge found here: https://www.hackerrank.com/challenges/maximum-element/problem
My solution produces the correct output, but times out on the final test cases beginning with #17.
Initially, I used a list and loop/recur to get my answer:
(defn get-query []
(map #(Integer/parseInt %) (clojure.string/split (read-line) #" ")))
(defn stack-stepper [query stack]
(condp = (first query)
1 (conj stack (second query))
2 (rest stack)
3 (do (println (apply max stack)) stack)))
(loop [stack '()
queries-left (Integer/parseInt (read-line))]
(if (> queries-left 0)
(recur (stack-stepper (get-query) stack) (dec queries-left))))
After some research and feedback from other channels, I tried a vector instead of a list, and reduce instead of loop/recur, but the results were the same.
(defn get-query []
(map #(Integer/parseInt %) (clojure.string/split (read-line) #" ")))
(defn get-queries []
(loop [queries []
queries-left (Integer/parseInt (read-line))]
(if (= queries-left 0)
queries
(recur (conj queries (get-query)) (dec queries-left)))))
(defn stack-stepper [stack query]
(condp = (first query)
1 (conj stack (second query))
2 (pop stack)
3 (do (println (apply max stack)) stack)))
(reduce stack-stepper [] (get-queries))
I am still new to FP and Clojure and I would really like to understand what I am missing. I greatly appreciate your time and help!
HackerRank problems are often very demanding from a performance point of view.
The obvious thing to try first is using a transient vector so see if that helps. I tried this:
(let [in (clojure.string/split (slurp *in*) #"\s")
tests (first in)
input-data (map #(Integer/parseInt %) (rest in))]
(loop [v (transient [])
d input-data]
(when (seq d)
(condp = (first d)
1 (recur (conj! v (second d)) (drop 2 d))
2 (recur (pop! v) (rest d))
3 (let [pv (persistent! v)] (println (apply max pv)) (recur (transient pv) (rest d)))))))
If failed at the same point as your solution. Clearly they're looking for something cleverer than that.
The obvious bottleneck is the calculation of the max value on the current stack, which gets re-calculated each time. We can instead save the previous max value on the stack, and recover it as the current max value when we pop the stack:
(defn peek! [tvec] (get tvec (dec (count tvec))))
(let [in (clojure.string/split (slurp *in*) #"\s")
tests (first in)
input-data (map #(Integer/parseInt %) (rest in))]
(loop [v (transient [])
m 0
d input-data]
(when (seq d)
(condp = (first d)
1 (let [snd (second d)
max-now (max m snd)]
(recur (conj! v {:val snd :max-prev m}) max-now (drop 2 d)))
2 (let [popped (peek! v)
max (if popped (:max-prev popped) 0)]
(recur (pop! v) max (rest d)))
3 (do
(println m)
(recur v m (rest d)))))))
Which puts me at rank 1 on the leaderboard :)
I have written a function that uses recursion to find the number of elements in a list and it works successfully however, I don't particularly like the way I've written it. Now I've written it one way I can't seem to think of a different way of doing it.
My code is below:
(def length
(fn [n]
(loop [i n total 0]
(cond (= 0 i) total
:t (recur (rest i)(inc total))))))
To me it seems like it is over complicated, can anyone think of another way this can be written for comparison?
Any help greatly appreciated.
Here is a naive recursive version:
(defn my-count [coll]
(if (empty? coll)
0
(inc (my-count (rest coll)))))
Bear in mind there's not going to be any tail call optimization going on here so for long lists the stack will overflow.
Here is a version using reduce:
(defn my-count [coll]
(reduce (fn [acc x] (inc acc)) 0 coll))
Here is code showing some different solutions. Normally, you should use the built-in function count.
(def data [:one :two :three])
(defn count-loop [data]
(loop [cnt 0
remaining data]
(if (empty? remaining)
cnt
(recur (inc cnt) (rest remaining)))))
(defn count-recursive [remaining]
(if (empty? remaining)
0
(inc (count-recursive (rest remaining)))))
(defn count-imperative [data]
(let [cnt (atom 0)]
(doseq [elem data]
(swap! cnt inc))
#cnt))
(deftest t-count
(is (= 3 (count data)))
(is (= 3 (count-loop data)))
(is (= 3 (count-recursive data)))
(is (= 3 (count-imperative data))))
Here's one that is tail-call optimized, and doesn't rely on loop. Basically the same as Alan Thompson's first one, but inner functions are the best things. (And feel more idiomatic to me.) :-)
(defn my-count [sq]
(letfn [(inner-count [c s]
(if (empty? s)
c
(recur (inc c) (rest s))))]
(inner-count 0 sq)))
Just for completeness, here is another twist
(defn my-count
([data]
(my-count data 0))
([data counter]
(if (empty? data)
counter
(recur (rest data) (inc counter)))))
I have the following functions that check for odd parity in sequence
(defn countOf[a-seq elem]
(loop [number 0 currentSeq a-seq]
(cond (empty? currentSeq) number
(= (first currentSeq) elem) (recur (inc number) (rest currentSeq))
:else (recur number (rest currentSeq))
)
)
)
(defn filteredSeq[a-seq elemToRemove]
(remove (set (vector (first a-seq))) a-seq)
)
(defn parity [a-seq]
(loop [resultset [] currentSeq a-seq]
(cond (empty? currentSeq) (set resultset)
(odd? (countOf currentSeq (first currentSeq))) (recur (concat resultset (vector(first currentSeq))) (filteredSeq currentSeq (first currentSeq)))
:else (recur resultset (filteredSeq currentSeq (first currentSeq)))
)
)
)
for example (parity [1 1 1 2 2 3]) -> (1 3) that is it picks odd number of elements from a sequence.
Is there a better way to achieve this?
How can this be done with reduce function of clojure
First, I decided to make more idiomatic versions of your code, so I could really see what it was doing:
;; idiomatic naming
;; no need to rewrite count and filter for this code
;; putting item and collection in idiomatic argument order
(defn count-of [elem a-seq]
(count (filter #(= elem %) a-seq)))
;; idiomatic naming
;; putting item and collection in idiomatic argument order
;; actually used the elem-to-remove argument
(defn filtered-seq [elem-to-remove a-seq]
(remove #(= elem-to-remove %) a-seq))
;; idiomatic naming
;; if you want a set, use a set from the beginning
;; destructuring rather than repeated usage of first
;; use rest to recur when the first item is guaranteed to be dropped
(defn idiomatic-parity [a-seq]
(loop [result-set #{}
[elem & others :as current-seq] a-seq]
(cond (empty? current-seq)
result-set
(odd? (count-of elem current-seq))
(recur (conj result-set elem) (filtered-seq elem others))
:else
(recur result-set (filtered-seq elem others)))))
Next, as requested, a version that uses reduce to accumulate the result:
;; mapcat allows us to return 0 or more results for each input
(defn reducing-parity [a-seq]
(set
(mapcat
(fn [[k v]]
(when (odd? v) [k]))
(reduce (fn [result item]
(update-in result [item] (fnil inc 0)))
{}
a-seq))))
But, reading over this, I notice that the reduce is just frequencies, a built in clojure function. And my mapcat was really just a hand-rolled keep, another built in.
(defn most-idiomatic-parity [a-seq]
(set
(keep
(fn [[k v]]
(when (odd? v) k))
(frequencies a-seq))))
In Clojure we can refine our code, and as we recognize places where our logic replicates the built in functionality, we can simplify the code and make it more clear. Also, there is a good chance the built in is better optimized than our own work-alikes.
Is there a better way to achieve this?
(defn parity [coll]
(->> coll
frequencies
(filter (fn [[_ v]] (odd? v)))
(map first)
set))
For example,
(parity [1 1 1 2 1 2 1 3])
;#{1 3}
How can this be done with reduce function of clojure.
We can use reduce to rewrite frequencies:
(defn frequencies [coll]
(reduce
(fn [acc x] (assoc acc x (inc (get acc x 0))))
{}
coll))
... and again to implement parity in terms of it:
(defn parity [coll]
(let [freqs (frequencies coll)]
(reduce (fn [s [k v]] (if (odd? v) (conj s k) s)) #{} freqs)))
What's the idiomatic way in Clojure to implement take-while-and-n-more below:
=> (take-while-and-n-more #(<= % 3) 1 (range 10))
(0 1 2 3 4)
My try is:
(defn take-while-and-n-more [pred n coll]
(let
[take-while-result (take-while pred coll)
n0 (count take-while-result)]
(concat
take-while-result
(into [] (take n (drop n0 coll))))))
I would use split-with, which is equivalent of getting results of both take-while and drop-while for the same parameters:
(defn take-while-and-n-more [pred n coll]
(let [[head tail] (split-with pred coll)]
(concat head (take n tail))))
Yet another way:
(defn take-while-and-n-more [pred n coll]
(let [[a b] (split-with pred coll)]
(concat a (take n b))))
The following code is a modified version of Clojures take-while. Where Clojures take-while returns nil as a default case (when the predicate does not match), this one invokes take to take the the additional items after the predicate fails.
Note that unlike versions using split-with, this version traverses the sequence only once.
(defn take-while-and-n-more
[pred n coll]
(lazy-seq
(when-let [s (seq coll)]
(if (pred (first s))
(cons (first s) (take-while-and-n-more pred n (rest s)))
(take n s)))))