How can you get the partial results from a map when an exception happens during execution?
i.e
(let [numbers [3 3 0 3]
results (map #(/ 3 %) numbers)]
results)
and return:
[3 3]
For example:
(let [numbers [3 3 0 3]
results (map
#(try (/ 3 %)
(catch Exception e e))
numbers)]
(take-while #(not (instance? Exception %)) results))
since thrown exception unwinds the stack up to the place where exception is caught (in your case it goes up to the top level), you can't operate on result after if. What you can do, is to manually put some value where the error was caught:
(let [numbers [3 3 0 3]
results (take-while number?
(map #(try
(/ 3 %)
(catch Throwable ex :error))
numbers))]
results)
Here's an approach using the cats library's exception monad:
(ns your-project.core
(:require [cats.monad.exception :as e]))
(let [numbers [3 3 0 3]
results (->> numbers
(map #(e/try-on (/ 3 %))) ; wrap division result in a try
(take-while e/success?) ; take values while successful
(mapv e/extract))] ; unwrap the values from the trys
results)
;; => [1 1]
And if you want to keep the values that come after the exception:
(let [numbers [3 3 0 3]
results (->> numbers
(map #(e/try-on (/ 3 %)))
(filter e/success?) ; filter all successful values
(mapv e/extract))]
results)
;; => [1 1 1]
Use keep:
(let [numbers [3 3 0 3]]
(keep #(try
(/ 3 %)
(catch RuntimeException _ nil)) numbers))
Related
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])))
I have to display the index of the odd items in a given list of numbers.
I tried getting the remainder but I have to divide the given list by [2 3 5 10] in order to know which element is odd.
(defn odd_one_out [y]
(println (map #(rem % 2) y)))
(odd_one_out [2 8 9 200 56])
I expect the output 9 or index of 9 since it is the only element which cannot be divided by 2.
The output i am getting is 0 0 1 0 0
If I understand correctly, you want to find the number which is uniquely indivisible for given divisors. You could use group-by to group the numbers by their divisibility, then find the one(s) that are indivisible by exactly one divisor.
(defn odd-one-out [nums divs]
(->> nums
(group-by #(map (fn [d] (zero? (mod % d))) divs))
(some (fn [[div-flags nums']]
(and (= 1 (count nums'))
(= 1 (count (filter true? div-flags)))
(first nums'))))))
(odd-one-out [2 8 9 200 56] [2 3 5 10]) ;; => 9
(odd-one-out [2 10 20 60 90] [2 3 5 10]) ;; => 2
If you just want to extend your current function, you could use map-indexed,which will give you this list ([0 0] [1 0] [2 1] [3 0] [4 0]), which you can then filter to keep only the vectors that have 1 in the second position. This will return the index of the odd character.
(defn odd-one-out [y]
(->> y
(map #(rem % 2))
(map-indexed vector)
(filter #(= 1 (second %)))
(map first)))
(odd-one-out [2 8 9 200 56])
(2)
Even better would be to use the function odd? from Clojure's standard library.
(->> [2 8 9 200 56]
(map odd?)
(map-indexed vector)
(filter #(second %))
(map first))
Another version using keep.
(to return the index)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(first %))))
(2)
(to return the value)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(second %))))
(9)
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)
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.
The task is to write a function that reverses a sequence. I am trying to do this as efficiently and clojure-ish as possible, but I can't figure out the best way. It doesn't feel right to create a variable and start appending items to that variable. What would seem idiomatic to me was if there was a way to do the following:
From the Clojure docs
(map-indexed (fn [idx itm] [idx itm]) "foobar")
--> ([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])
What I have done is this:
(defn testing [x]
(map-indexed (fn [idx itm] [(- (count x) idx) itm]) x))
Which yields:
(testing "foobar")
--> ([6 \f] [5 \o] [4 \o] [3 \b] [2 \a] [1 \r])
What I can't figure out is how to essentially pack that back up into a new list with the correct indexes. Honestly, even the concept of declaring a variable is escaping me in Clojure at the moment. All my experience is with Python and Ruby.
Strings are sequable so we can use clojure.core/reduce
(defn rev [x]
(reduce #(str %2 %1) x))
(rev "foobar") ;; "raboof"
The idea is that for each iteration, we create a new string that is the next character in the sequence prepended to the current string.
All my experience is with Python and Ruby
Here is the same in Ruby:
def rev(x)
x.chars.reduce { |s, c| c + s }
end
For non-strings
(defn rev [x]
(reduce conj () x))
(rev [1 2 3 4 5]) ;; (5 4 3 2 1)
You can reverse a sequence using indexes, as your question proposes, as follows:
(defn reverse [s]
(let [v (vec s)] (map v (range (dec (count v)) -1 -1))))
... or, perversely,
(def reverse (comp rseq vec))