I am working on some Lisp exercises using Clojure. I am trying to work these exercises without taking advantage of vectors and some Clojure functions.
This function
(defn rev-seq
[s1]
(concat (pop s1) (list (peek s1))))
puts the first element of a list at the end. I want to call this function as many times as it takes to reverse the list (without calling Clojure's reverse function).
I am not sure what to use in its place. I have experimented with map, apply, and repeat with no success. I would rather have a way to think differently about this than a straight answer, but I am not asking for a discussion.
Firstly, I think you'll need to convert rev-seq to use first/rest rather than peek/pop if you want to work on general sequences - at leas in Clojure 1.4 peek/pop seems to require a PersistentStack:
(defn rev-seq
[s1]
(concat (rest s1) (list (first s1))))
Then you should probably note that applying this function repeatedly will "cycle" a list rather than reversing it. You can see that if you look at the result of a small number of applications using iterate:
(def s '(1 2 3 4 5 6 7 8 9))
(nth (iterate rev-seq s) 3)
=> (4 5 6 7 8 9 1 2 3)
An option that would work is to reverse with a recursive function:
(defn reverse-seq [s]
(concat (reverse (next s)) (list (first s))))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Or alternatively you can do a reverse using the technique in clojure.core:
(defn reverse-seq [s]
(reduce conj () s))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Hope this gives you some ideas!
Recursion is powerful!
I translated
the solution
into Clojure.
(defn- inverte-aux
[lista resto]
(if lista
(recur (next lista) (cons (first lista) resto))
resto))
(defn inverte
[lista]
(inverte-aux lista nil))
user> (inverte [4 3 2 1 3])
(3 1 2 3 4)
Related
I'm currently learning Clojure, and I'm trying to learn how to do things the best way. Today I'm looking at the basic concept of doing things on a sequence, I know the basics of map, filter and reduce. Now I want to try to do a thing to pairs of elements in a sequence, and I found two ways of doing it. The function I apply is println. The output is simply 12 34 56 7
(def xs [1 2 3 4 5 6 7])
(defn work_on_pairs [xs]
(loop [data xs]
(if (empty? data)
data
(do
(println (str (first data) (second data)))
(recur (drop 2 data))))))
(work_on_pairs xs)
I mean, I could do like this
(map println (zipmap (take-nth 2 xs) (take-nth 2 (drop 1 xs))))
;; prints [1 2] [3 4] [5 6], and we loose the last element because zip.
But it is not really nice.. My background is in Python, where I could just say zip(xs[::2], xs[1::2]) But I guess this is not the Clojure way to do it.
So I'm looking for suggestions on how to do this same thing, in the best Clojure way.
I realize I'm so new to Clojure I don't even know what this kind of operation is called.
Thanks for any input
This can be done with partition-all:
(def xs [1 2 3 4 5 6 7])
(->> xs
(partition-all 2) ; Gives ((1 2) (3 4) (5 6) (7))
(map (partial apply str)) ; or use (map #(apply str %))
(apply println))
12 34 56 7
The map line is just to join the pairs so the "()" don't end up in the output.
If you want each pair printed on its own line, change (apply println) to (run! println). Your expected output seems to disagree with your code, so that's unclear.
If you want to dip into transducers, you can do something similar to the threading (->>) form of the accepted answer, but in a single pass over the data.
Assuming
(def xs [1 2 3 4 5 6 7])
has been evaluated already,
(transduce
(comp
(partition-all 2)
(map #(apply str %)))
conj
[]
xs)
should give you the same output if you wrap it in
(apply println ...)
We supply conj (reducing fn) and [] (initial data structure) to specify how the reduce process inside transduce should build up the result.
I wouldn't use a transducer for a list that small, or a process that simple, but it's good to know what's possible!
I'm learning Clojure and actually I'm doing some exercises to practice but I'm stuck in a problem:
I need to make a sum-consecutives function which sums consecutive elements in a array, resulting in a new one, as example:
[1,4,4,4,0,4,3,3,1] ; should return [1,12,0,4,6,1]
I made this function which should work just fine:
(defn sum-consecutives [a]
(reduce #(into %1 (apply + %2)) [] (partition-by identity a)))
But it throws an error:
IllegalArgumentException Don't know how to create ISeq from:
java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
Can anyone help me see what is wrong with my func? I've already search this error in web but I find no helpful solutions.
You'll likely want to use conj instead of into, as into is expecting its second argument to be a seq:
(defn sum-consecutives [a]
(reduce
#(conj %1 (apply + %2))
[]
(partition-by identity a)))
(sum-consecutives [1,4,4,4,0,4,3,3,1]) ;; [1 12 0 4 6 1]
Alternatively, if you really wanted to use into, you could wrap your call to apply + in a vector literal like so:
(defn sum-consecutives [a]
(reduce
#(into %1 [(apply + %2)])
[]
(partition-by identity a)))
Your approach is sound in starting with partition-by. But let's
walk through the steps to sum each subsequence that it produces.
(let [xs [1 4 4 4 0 4 3 3 1]]
(partition-by identity xs)) ;=> ((1) (4 4 4) (0) (4) (3 3) (1))
To get a sum, you can use reduce (though a simple apply
instead would also work
here); e.g.:
(reduce + [4 4 4]) ;=> 12
Now put it all together to reduce each subsequence from above with map:
(let [xs [1 4 4 4 0 4 3 3 1]]
(map #(reduce + %) (partition-by identity xs))) ;=> (1 12 0 4 6 1)
A few notes...
I'm using xs to represent your vector (as suggested by the
Clojure Style Guide).
The let is sometimes a convenient form for experimenting with some
data building up to eventual functions.
Commas are not needed and are usually distracting, except occasionally
with hash-maps.
So your final function based on all this could look something like:
(defn sum-consecutives [coll]
(map #(reduce + %) (partition-by identity coll)))
I am not understand why instead of normal list I recive (clojure.core/seq).
My code
(defn del-list [arg-list lvl] (do
(cond
(= lvl 1) (remove seq? arg-list)
:else (map #(if (seq? %)
(del-list % (- lvl 1))
%
) arg-list)
)
))
(println (del-list `(1 2 3 `(1 2 `(1 2 3) 3) 1 2 3) 2))
;result=> (1 2 3 (clojure.core/seq) 1 2 3)
Why is this happening? I don't know how valid search this, all links from google point me to documentation about seq and seq?.
Like #ClojureMostly says in the comments, don't use bacticks, use a single quote. Also don't nest them, one is enough.
So, calling your function like this:
(println (del-list '(1 2 3 (1 2 (1 2 3) 3) 1 2 3) 2))
Will solve your immediate problem.
Going into a bit more depth, there are some differencences between single quote (just called quote) and backtick (called syntax quote).
In quoting something, you say that you want just the data structure, that it shouldn't be evaluated as code. In clojure, code is data, so (+ 1 2) is a list with a symbol and two numbers which, when evaluated as code, evals to 3. So, (+ 1 2) => 3 and '(+ 1 2) => (+ 1 2).
Syntax quote is similar, but it looks up the namespaces of things and you can unquote stuff inside. This makes it useful for writing macros.
;; Looks up the namespaces of symbols to avoid the problem of variable capture
`(+ 1 2) ;=> (clojure.core/+ 1 2)
;; You can unquote parts of the expression.
;; ~ is unquote ~# is unqoute splicing
;; That should give you the vocabulary to google this.
`(+ 1 2 3 ~(* 2 2)) ;=> (clojure.core/+ 1 2 3 4)
Nested quotes are never what you want. (Unless you alternate quoting and unquoting, and even then it's usually confusing)
In clojure you'd usually represent sequential things as vectors [1 2 3] (O(n) random access, grows at the end), unless you specifically want some property of a linked list for your data. (Like representing a stack, as lists efficiently add and remove the first element.)
(defn del-list [arg-list lvl]
;; You don't need the do, there's an implicit do in many special forms
;; like let, fn and defn
;; Also you only had one thing in your do, in that case it doesn't do anything
;; There's only one condition, so I'd use if instead of cond
(if (= lvl 1)
;; And, like someone mentioned in the comments,
;; what you probably want is sequential? instead of seq?
(remove sequential? arg-list)
(map #(if (sequential? %)
(del-list % (dec lvl)) ; dec stands for decrement
%)
arg-list)))
;; This works
(println (del-list '(1 2 3 (1 2 (1 2 3) 3) 1 2 3) 2))
;; But this is more idiomatic (modulo specific reasons to prefer lists)
(println (del-list [1 2 3 [1 2 [1 2 3] 3] 1 2 3] 2))
;; If you change map to mapv, and wrap remove with vec it will return vectors
(defn del-vec [arg-vec lvl]
(if (= lvl 1)
(vec (remove sequential? arg-vec))
(mapv #(if (sequential? %)
(del-vec % (dec lvl)) ; dec stands for decrement
%)
arg-vec)))
(println (del-vec [1 2 3 [1 2 [1 2 3] 3] 1 2 3] 2))
;; But most of the time you don't care about the specific type of sequential things
As for your actual question, why does clojure.core/seq appear, I have no idea. That's not how you use quoting, so it has never come up.
I have a higher order predicate
(defn not-factor-of-x? [x]
(fn [n]
(cond
(= n x) true
(zero? (rem n x)) false
:else true)))
which returns a predicate that checks if the given argument n is not a factor of x.
Now I want to filter a list of numbers and find which are not factors of say '(2 3). One way to do this would be :
(filter (not-factor-of-x? 3) (filter (not-factor-of-x? 2) (range 2 100)))
But one can only type so much. In order to do this dynamically I tried function composition :
(comp (partial filter (not-factor-of-x? 2)) (partial filter (not-factor-of-x? 3)))
And it works. So I tried reducing the filters, like this:
(defn compose-filters [fn1 fn2]
(comp (partial filter fn1) (partial filter fn2)))
(def composed-filter (reduce compose-filters (map not-factor-of-x? '(2 3 5 7 11))))
(composed-filter (range 2 122)) ; returns (2 3 4 5 6 7 8 9 10 .......)
So, why the filter composition is not working as intended ?
There are many ways to compose functions and/or improve your code. Here's one:
(defn factor? [n x]
(and (not= n x) (zero? (rem n x))))
(->> (range 2 100)
(remove #(factor? % 2))
(remove #(factor? % 3)))
;; the same as the above
(->> (range 2 100)
(remove (fn [n] (some #(factor? n %) [2 3]))))
To see your problem with (reduce compose-filters ... let's look a bit at what that actually does. First, it uses filter on the first two predicates and composes them.. The result of that is a new function from sequences to sequences. The next iteration then calls filter on that function, when filter expects a predicate. Every sequence is a truthy value, so that new filter will now never remove any values because it's using a "predicate" which always returns truthy values. So in the end, only the very last filter actually does any filtering - in my REPL your code removes the numbers 22, 33, 44 and so on because 11 is a factor in them. I think the reduce you want to do here is more like
(reduce comp (map (comp (partial partial filter) not-factor-of-x?) '(2 3 5 7 11)))
Note how because we only want to call (partial filter) once per number, you can move that into the mapping step of the mapreduce. As to how I'd do this, considering that you produce all your predicates together:
(map not-factor-of-x? '(2 3 5 7 11))
it seems more natural to me to just combine the predicates at that point using every-pred
(apply every-pred (map not-factor-of-x? '(2 3 5 7 11)))
and use one filter on that predicate. It seems to communicate the intent a little more clearly ("I want values satisfying every one of these preds") and unlike composition of (partial filter ...) it avoids making an intermediate sequence for each predicate.
(In Clojure 1.7+ you can also avoid this by composing the transducer version of filter).
I'm looking for an elegant way to generate a sequence of the rolling average of a sequence of numbers. Hopefully something more elegant than using lazy-seq
Without any consideration of efficiency:
(defn average [lst] (/ (reduce + lst) (count lst)))
(defn moving-average [window lst] (map average (partition window 1 lst)))
user> (moving-average 5 '(1 2 3 4 5 6 7 8))
(3 4 5 6)
If you need it to be fast, there are some fairly obvious improvements to be made!
But it will get less elegant.
There's a very similar question on SO: Calculating the Moving Average of a List. It's more general -- a number of FP-friendly languages are represented, with the accepted answer using Scala -- but there are a few nice Clojure solutions.
I've posted my own solution over there. Note that it does use lazy-seq, but that's because I wanted it to perform well for large periods (which means adjusting the average at each step rather than calculating a separate average for each window of size = period into the input list). Look around that Q for nice solutions which made the other tradeoff, resulting in shorter code with a somewhat more declarative feel, which actually performs better for very short periods (although suffers significant slowdowns for longer periods, as is to be expected).
This version is a bit faster, especially for long windows, since it keeps a rolling sum and avoids repeatedly adding the same things.
Because of the lazy-seq, it's also perfectly general and won't blow stack
(defn partialsums [start lst]
(lazy-seq
(if-let [lst (seq lst)]
(cons start (partialsums (+ start (first lst)) (rest lst)))
(list start))))
(defn sliding-window-moving-average [window lst]
(map #(/ % window)
(let [start (apply + (take window lst))
diffseq (map - (drop window lst) lst)]
(partialsums start diffseq))))
;; To help see what it's doing:
(sliding-window-moving-average 5 '(1 2 3 4 5 6 7 8 9 10 11))
start = (+ 1 2 3 4 5) = 15
diffseq = - (6 7 8 9 10 11)
(1 2 3 4 5 6 7 8 9 10 11)
= (5 5 5 5 5 5)
(partialsums 15 '(5 5 5 5 5 5) ) = (15 20 25 30 35 40 45)
(map #(/ % 5) (20 25 30 35 40 45)) = (3 4 5 6 7 8 9)
;; Example
(take 20 (sliding-window-moving-average 5 (iterate inc 0)))
Instead of the partialsums fn (which is helpful to see what's going on), you can use reductions in clojure.core:
(defn sliding-window-moving-average [window lst]
(map #(/ % window)
(let [start (apply + (take window lst))
diffseq (map - (drop window lst) lst)]
(reductions + start diffseq))))