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])))
Related
(defn mapset [func ele]
(loop [elements ele
result []]
(if (empty? elements)
(set result)
(let [[first-value & another] elements]
(into result (func first-value))
(recur another result)))))
(def v [1 2 3 4 5])
(mapset + v)
Exeption:
Don't know how to create ISeq from: java.lang.Long
Who knows how to fix it?
The first issue is that into accepts collections, not a collection and a single element. I think you wanted to use conj instead:
(conj result (func first-value))
Another issue is that Clojure collections (result vector in this case) are immutable thus functions like conj or into return a new updated collection instead of modifying their input parameters thus you need to use their result for recur:
(recur another (conj result (func first-value)))
And the last issue is that you are passing + function which when applied to a single argument will return it. I guess you wanted to use inc instead.
Thus your working code should look like:
(defn mapset [func ele]
(loop [elements ele
result []]
(if (empty? elements)
(set result)
(let [[first-value & another] elements]
(recur another (conj result (func first-value)))))))
(def v [1 2 3 4 5])
(mapset inc v)
;; => #{4 6 3 2 5}
I am coming from a Java background trying to learn Clojure. As the best way of learning is by actually writing some code, I took a very simple example of finding even numbers in a vector. Below is the piece of code I wrote:
`
(defn even-vector-2 [input]
(def output [])
(loop [x input]
(if (not= (count x) 0)
(do
(if (= (mod (first x) 2) 0)
(do
(def output (conj output (first x)))))
(recur (rest x)))))
output)
`
This code works, but it is lame that I had to use a global symbol to make it work. The reason I had to use the global symbol is because I wanted to change the state of the symbol every time I find an even number in the vector. let doesn't allow me to change the value of the symbol. Is there a way this can be achieved without using global symbols / atoms.
The idiomatic solution is straightfoward:
(filter even? [1 2 3])
; -> (2)
For your educational purposes an implementation with loop/recur
(defn filter-even [v]
(loop [r []
[x & xs :as v] v]
(if (seq v) ;; if current v is not empty
(if (even? x)
(recur (conj r x) xs) ;; bind r to r with x, bind v to rest
(recur r xs)) ;; leave r as is
r))) ;; terminate by not calling recur, return r
The main problem with your code is you're polluting the namespace by using def. You should never really use def inside a function. If you absolutely need mutability, use an atom or similar object.
Now, for your question. If you want to do this the "hard way", just make output a part of the loop:
(defn even-vector-3 [input]
(loop [[n & rest-input] input ; Deconstruct the head from the tail
output []] ; Output is just looped with the input
(if n ; n will be nil if the list is empty
(recur rest-input
(if (= (mod n 2) 0)
(conj output n)
output)) ; Adding nothing since the number is odd
output)))
Rarely is explicit looping necessary though. This is a typical case for a fold: you want to accumulate a list that's a variable-length version of another list. This is a quick version:
(defn even-vector-4 [input]
(reduce ; Reducing the input into another list
(fn [acc n]
(if (= (rem n 2) 0)
(conj acc n)
acc))
[] ; This is the initial accumulator.
input))
Really though, you're just filtering a list. Just use the core's filter:
(filter #(= (rem % 2) 0) [1 2 3 4])
Note, filter is lazy.
Try
#(filterv even? %)
if you want to return a vector or
#(filter even? %)
if you want a lazy sequence.
If you want to combine this with more transformations, you might want to go for a transducer:
(filter even?)
If you wanted to write it using loop/recur, I'd do it like this:
(defn keep-even
"Accepts a vector of numbers, returning a vector of the even ones."
[input]
(loop [result []
unused input]
(if (empty? unused)
result
(let [curr-value (first unused)
next-result (if (is-even? curr-value)
(conj result curr-value)
result)
next-unused (rest unused) ]
(recur next-result next-unused)))))
This gets the same result as the built-in filter function.
Take a look at filter, even? and vec
check out http://cljs.info/cheatsheet/
(defn even-vector-2 [input](vec(filter even? input)))
If you want a lazy solution, filter is your friend.
Here is a non-lazy simple solution (loop/recur can be avoided if you apply always the same function without precise work) :
(defn keep-even-numbers
[coll]
(reduce
(fn [agg nb]
(if (zero? (rem nb 2)) (conj agg nb) agg))
[] coll))
If you like mutability for "fun", here is a solution with temporary mutable collection :
(defn mkeep-even-numbers
[coll]
(persistent!
(reduce
(fn [agg nb]
(if (zero? (rem nb 2)) (conj! agg nb) agg))
(transient []) coll)))
...which is slightly faster !
mod would be better than rem if you extend the odd/even definition to negative integers
You can also replace [] by the collection you want, here a vector !
In Clojure, you generally don't need to write a low-level loop with loop/recur. Here is a quick demo.
(ns tst.clj.core
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(defn is-even?
"Returns true if x is even, otherwise false."
[x]
(zero? (mod x 2)))
; quick sanity checks
(spyx (is-even? 2))
(spyx (is-even? 3))
(defn keep-even
"Accepts a vector of numbers, returning a vector of the even ones."
[input]
(into [] ; forces result into vector, eagerly
(filter is-even? input)))
; demonstrate on [0 1 2...9]
(spyx (keep-even (range 10)))
with result:
(is-even? 2) => true
(is-even? 3) => false
(keep-even (range 10)) => [0 2 4 6 8]
Your project.clj needs the following for spyx to work:
:dependencies [
[tupelo "0.9.11"]
I need a function that maps a function only on every other element, e.g.
(f inc '(1 2 3 4))
=> '(2 2 4 4)
I came up with:
(defn flipflop [f l]
(loop [k l, b true, r '()]
(if (empty? k)
(reverse r)
(recur (rest k)
(not b)
(conj r (if b
(f (first k))
(first k)))))))
Is there a prettier way to achieve this ?
(map #(% %2)
(cycle [f identity])
coll)
It's a good idea to look at Clojure's higher level functions before using loop and recur.
user=> (defn flipflop
[f coll]
(mapcat #(apply (fn ([a b] [(f a) b])
([a] [(f a)]))
%)
(partition-all 2 coll)))
#'user/flipflop
user=> (flipflop inc [1 2 3 4])
(2 2 4 4)
user=> (flipflop inc [1 2 3 4 5])
(2 2 4 4 6)
user=> (take 11 (flipflop inc (range))) ; demonstrating laziness
(1 1 3 3 5 5 7 7 9 9 11)
this flipflop doesn't need to reverse the output, it is lazy, and I find it much easier to read.
The function uses partition-all to split the list into pairs of two items, and mapcat to join a series of two element sequences from the calls back into a single sequence.
The function uses apply, plus multiple arities, in order to handle the case where the final element of the partitioned collection is a singleton (the input was odd in length).
also, since you want to apply the function to some specific indiced items in the collection (even indices in this case) you could use map-indexed, like this:
(defn flipflop [f coll]
(map-indexed #(if (even? %1) (f %2) %2) coll))
Whereas amalloy's solution is the one, you could simplify your loop - recur solution a bit:
(defn flipflop [f l]
(loop [k l, b true, r []]
(if (empty? k)
r
(recur (rest k)
(not b)
(conj r ((if b f identity) (first k)))))))
This uses couple of common tricks:
If an accumulated list comes out in the wrong order, use a vector
instead.
Where possible, factor out common elements in a conditional.
I am playing around and trying to create my own reductions implementation, so far I have this which works with this test data:
((fn [func & args]
(reduce (fn [acc item]
(conj acc (func (last acc) item))
)[(first args)] (first (rest args)))) * 2 [3 4 5]
What I don't like is how I am separating the args.
(first args) is what I would expect, i.e. 2 but (rest args) is ([3 4 5]) and so I am getting the remainder like this (first (rest args)) which I do not like.
Am I missing some trick that makes it easier to work with variadic arguments?
Variadic arguments are just about getting an unspecified number of arguments in a list, so all list/destructuring operations can be applied here.
For example:
(let [[fst & rst] a-list]
; fst is the first element
; rst is the rest
)
This is more readable than:
(let [fst (first a-list)
rst (rest a-list)]
; ...
)
You can go further to get the first and second elements of a list (assuming it has >1 elements) in one line:
(let [fst snd & rst]
; ...
)
I originally misread your question and thought you were trying to reimplement the reduce function. Here is a sample implementation I wrote for this answer which does’t use first or rest:
(defn myreduce
;; here we accept the form with no initial value
;; like in (myreduce * [2 3 4 5]), which is equivalent
;; to (myreduce * 2 [3 4 5]). Notice how we use destructuring
;; to get the first/rest of the list passed as a second
;; argument
([op [fst & rst]] (myreduce op fst rst))
;; we take an operator (function), accumulator and list of elements
([op acc els]
;; no elements? give the accumulator back
(if (empty? els)
acc
;; all the function's logic is in here
;; we're destructuring els to get its first (el) and rest (els)
(let [[el & els] els]
;; then apply again the function on the same operator,
;; using (op acc el) as the new accumulator, and the
;; rest of the previous elements list as the new
;; elements list
(recur op (op acc el) els)))))
I hope it helps you see how to work with list destructuring, which is probably what you want in your function. Here is a relevant blog post on this subject.
Tidying up your function.
As #bfontaine commented, you can use (second args) instead of (first (rest args)):
(defn reductions [func & args]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[(first args)]
(second args)))
This uses
func
(first args)
(second args)
... but ignores the rest of args.
So we can use destructuring to name the first and second elements of args - init and coll seem suitable - giving
(defn reductions [func & [init coll & _]]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[init]
coll))
... where _ is the conventional name for the ignored argument, in this case a sequence.
We can get rid of it, simplifying to
(defn reductions [func & [init coll]] ... )
... and then to
(defn reductions [func init coll] ... )
... - a straightforward function of three arguments.
Dealing with the underlying problems.
Your function has two problems:
slowness
lack of laziness.
Slowness
The flashing red light in this function is the use of last in
(fn [acc item] (conj acc (func (last acc) item)))
This scans the whole of acc every time it is called, even if acc is a vector. So this reductions takes time proportional to the square of the length of coll: hopelessly slow for long sequences.
A simple fix is to replace (last acc) by (acc (dec (count acc))), which takes effectively constant time.
Lack of laziness
We still can't lazily use what the function produces. For example, it would be nice to encapsulate the sequence of factorials like this:
(def factorials (reductions * 1N (next (range)))))
With your reductions, this definition never returns.
You have to entirely recast your function to make it lazy. Let's modify the standard -lazy -reductions to employ destructuring:
(defn reductions [f init coll]
(cons
init
(lazy-seq
(when-let [[x & xs] (seq coll)]
(reductions f (f init x) xs)))))
Now we can define
(def factorials (reductions * 1N (next (range))))
Then, for example,
(take 10 factorials)
;(1N 1N 2N 6N 24N 120N 720N 5040N 40320N 362880N)
Another approach is to derive the sequence from itself, like a railway locomotive laying the track it travels on:
(defn reductions [f init coll]
(let [answer (lazy-seq (reductions f init coll))]
(cons init (map f answer coll))))
But this contains a hidden recursion (hidden from me, at least):
(nth (reductions * 1N (next (range))) 10000)
;StackOverflowError ...
I'm using Project Euler questions to help me learn clojure, and I've run into an exception I can't figure out. nillify and change-all are defined at the bottom for reference.
(loop [the-vector (vec (range 100))
queue (list 2 3 5 7)]
(if queue
(recur (nillify the-vector (first queue)) (next queue))
the-vector))
This throws a NullPointerException, and I can't figure out why. The only part of the code I can see that could throw such an exception is the call to nillify, but it doesn't seem like queue ever gets down to just one element before the exception is thrown---and even if queue were to become empty, that's what the if statement is for.
Any ideas?
"given a vector, a value, and a list of indices, return a vector w/everthing # indice=value"
(defn change-all [the-vector indices val]
(apply assoc the-vector (interleave indices (repeat (count indices) val))))
"given a vector and a val, return a vector in which all entries with indices equal to multiples of val are nilled, but leave the original untouched"
(defn nillify [coll val]
(change-all coll (range (* 2 val) (inc (last coll)) val) nil))
The problem sexpr is
(inc (last coll))
You're changing the contents of the vector, you can't use this to determine the length anymore. Instead:
(count coll)
As a matter of style, use let bindings:
(defn change-all [the-vector indices val]
(let [c (count indices)
s (interleave indices (repeat c val))]
(apply assoc the-vector s)))
(defn nillify [coll val]
(let [c (count coll)
r (range (* 2 val) c val)]
(change-all coll r nil)))
(loop [the-vector (vec (range 100))
[f & r] '(2 3 5 7)]
(if r
(recur (nillify the-vector f) r)
the-vector))