if key exists: update, otherwise: assoc - clojure

consider this inside a reduce loop:
(if (contains? m k)
(update m k conj v)
(assoc m k [v]))
Is there a way to get rid of the if statement?

Use fnil to handle the nil value of v when k doesn't exist in the map:
(update m k (fnil conj []) v)

While the fnil answer is more spectacular, I find the following easier to read, especially if unfamiliar with fnil:
(assoc m k (conj (m k []) v))
where (m k []) returns the value of k in m or defaults to [] if k does not exist in m.
If k is a symbol, (k m []) would also work.

Related

collect function of Lisp in Clojure

I defined a function is-prime? in Clojure that returns if a number is prime or not, and I am trying to define a function prime-seq that returns all the prime numbers between two numbersn and m.
I have created the function in Common Lisp since I am more comfortable with it and I am trying to translate the code to Clojure. However, I cannot find how to replace the collect function in Lisp to Clojure.
This is my prime-seq function in Lisp:
(defun prime-seq (i j)
(loop for x from i to j
when (is-prime x)
collect x
)
)
And this is the try I did in Clojure but it is not working:
(defn prime-seq? [n m]
(def list ())
(loop [k n]
(cond
(< k m) (if (prime? k) (def list (conj list k)))
)
)
(println list)
)
Any ideas?
loop in Clojure is not the same as CL loop. You probably want for:
(defn prime-seq [i j]
(for [x (range i j)
:when (is-prime x)]
x))
Which is basically the same as saying:
(defn prime-seq [i j]
(filter is-prime (range i j)))
which may be written using the ->> macro for readability:
(defn prime-seq [i j]
(->> (range i j)
(filter is-prime)))
However, you might actually want a lazy-sequence of all prime numbers which you could write with something like this:
(defonce prime-seq
(let [c (fn [m numbers] (filter #(-> % (mod m) (not= 0)) numbers))
f (fn g [s]
(when (seq s)
(cons (first s)
(lazy-seq (g (c (first s) (next s)))))))]
(f (iterate inc 2))))
The lazy sequence will cache the results of the previous calculation, and you can use things like take-while and drop-while to filter the sequence.
Also, you probably shouldn't be using def inside a function call like that. def is for defining a var, which is essentially global. Then using def to change that value completely destroys the var and replaces it with another var pointing to the new state. It's something that's allowed to enable iterative REPL based development and shouldn't really be used in that way. Var's are designed to isolate changes locally to a thread, and are used as containers for global things like functions and singletons in your system. If the algorithm you're writing needs a local mutable state you could use a transient or an atom, and define a reference to that using let, but it would be more idiomatic to use the sequence processing lib or maybe a transducer.
Loop works more like a tail recursive function:
(defn prime-seq [i j]
(let [l (transient [])]
(loop [k i]
(when (< k j)
(when (is-prime k)
(conj! l k))
(recur (inc k))))
(persistent! l)))
But that should be considered strictly a performance optimisation. The decision to use transients shouldn't be taken lightly, and it's often best to start with a more functional algorithm, benchmark and optimise accordingly. Here is a way to write the same thing without the mutable state:
(defn prime-seq [i j]
(loop [k i
l []]
(if (< k j)
(recur (inc k)
(if (is-prime k)
(conj l k)
l))
l)))
I'd try to use for:
(for [x (range n m) :when (is-prime? x)] x)

Arity overloading in Clojure source code [duplicate]

This question already has answers here:
Why clojure's vector function definition is so verbose?
(2 answers)
Closed 5 years ago.
Here's the source code for update-in:
(defn update-in
([m [k & ks] f]
(if ks
(assoc m k (update-in (get m k) ks f))
(assoc m k (f (get m k)))))
([m [k & ks] f a]
(if ks
(assoc m k (update-in (get m k) ks f a))
(assoc m k (f (get m k) a))))
([m [k & ks] f a b]
(if ks
(assoc m k (update-in (get m k) ks f a b))
(assoc m k (f (get m k) a b))))
([m [k & ks] f a b c]
(if ks
(assoc m k (update-in (get m k) ks f a b c))
(assoc m k (f (get m k) a b c))))
([m [k & ks] f a b c & args]
(if ks
(assoc m k (apply update-in (get m k) ks f a b c args))
(assoc m k (apply f (get m k) a b c args)))))
As far as I know (and I don't now much), this always gives the same result:
(defn my-update-in2
([m [k & ks ] f & args]
(if ks
(assoc m k (apply update-in (get m k) ks f args))
(assoc m k (apply f (get m k) args)))))
My question: why isn't update-in (and many other Clojure functions) implemented this way? I would guess there are performance issues, ie. not using apply is faster.
Yes, you have guessed it correctly: some of the arities exist because of the performance cost of apply.
Having explicit arities for the most common cases (e.g. up to 3 arguments to the f function) improves performance as it translates to a direct function call.

Building a nested vector in Clojure

My goal is to build a nested vector of dimension n consisting of a single element p. As an example let me choose n=2 and p=1, so the output would be:
[[1 1] [1 1]]
Probably, you want something like this:
(defn square-matrix [n p]
(->> p (repeat n) (repeat n)))
Or, if you need vectors (not seqs):
(defn square-matrix [n p]
(->> p (repeat n) vec (repeat n) vec))
I think what you want is (->> p (repeat n) vec (repeat n) vec).
(defn vec-of-dim [n e]
(->> (repeat n e)
(into [])
(repeat n)
(into [])))

how to use Conj function in Clojure

I am trying to achieve one of the functions in my program. I have list=[a b c] as a parameter in func3. I want to test an equality of these items. If they are not equal I will call it again using another list return from func2.
Here is what I need to do. I want the Conj to do this [list list1 list2 list3] until func3 have the items that are equal. In my function, I want conj to merge an empty vector r[] to other lists when the condition is false.All I get right now is a final list return when the condition is true. Assume that the condition must be false(items are not equal) before getting true. Can someone help me to use the conj in the false condition.Thank you.
;input [1 2 3]
;output [[1 2 3][1 3 4] [3 4 5] ]// numbers for demo only
(defn func3 [list]
(loop [v (vec list) r []]
(if(= (v 0) (v 1) (v 2))
(conj r v)
(let[result (func2 v)]
;i want to merge result to r until the condition is true
(conj r result)
(func3 result)))))
Conj never changes its input, it creates a new output based on the input. In the second condition, you are not doing anything to the output of conj, so its result is never used.
(defn func3 [list]
(loop [[v & vs] (vec list) r []]
(if (= (v 0) (v 1) (v 2))
(conj r v)
(let [result (func2 v)
r (conj r result)]
(recur vs r)))))
I understand that you have a list of three elements as an initial input, want to compare them for equality. In case they match, you want to append the list to a later returned accumulator - in case they don't, you want to transform the list using a function idiomatically called func2 and try that procedure again.
EDIT: Since you have commented how your function should work, here comes an implementation:
(defn func3
"Determines whether items in coll are equal. If not, transforms coll with func2 and
repeats the test until a coll with equal elements could be found.
Returns a vector of all tried versions."
[coll]
(loop [acc []
coll coll]
(if (apply = coll)
(conj acc coll)
(recur (conj acc coll)
(func2 coll)))))
Here is a lazy implementation:
(defn func3
[coll]
(-> (->> coll
(iterate func2)
(split-with (partial apply =)))
(as-> [dropped [r]]
(concat dropped [r])))

Sparsely populated multidimensional vector in clojure?

I'm trying to create a sparsely populated multidimensional vector in Clojure, but I'm coming up against the limits of my knowledge.
I have a collection x I'm iterating over, and I want to create a multidimensional vector of size (count x) by (count x). Most of the cells will be empty, but at each point where the x and y axes match (e.g., (1 1), (2 2), (3 3), etc.), I need to run a function to see if a value should be put in that space.
In a procedural language, it would be something like:
for (i = 0; i < length(x); i++) {
for (j = 0; j < length(x); j++) {
if (i == j && testReturnsTrue(x[i])) {
table[i][j] = (list x[i])
}
else {
table[i][j] = ()
}
}
}
But I can't wrap my head around how this would be done in Clojure. I tried using nested for comprehensions and nested loop-recur structures but I can't get either to work.
Alternatively, I could create a mutable table with the right sizes, initialize it all to empty lists, and then set the values as I check each element in x, but I'd like to keep the table immutable if possible.
Use a hashmap? There's no need for a vector, which can't be sparse. Plus, this imperative solution looks like it's not sparse either - it's wasting memory storing zillions of empty cells. Perhaps something like this:
(let [indexed (map-indexed vector xs)]
(reduce (fn [m [i x]]
(if (test? x)
(assoc-in m [i i] x)
m))
{}
indexed))
Nested fors is how I would do it:
(def x [:a :b :c :d])
(vec (for [i (range (count x))]
(vec (for [j (range (count x))]
(if (and (= i j) (identity (x i)))
[(x i)]
[])))))
=> [[[:a] [] [] []] [[] [:b] [] []] [[] [] [:c] []] [[] [] [] [:d]]]
(identity (x i)) is a stand-in for some kind of test.
EDIT: As mentioned in other answers, if this structure remains sparsely populated, a hash-map is a better choice. I was assuming you would be populating the empty portions in later computations.