Subtract n from every element of a Clojure sequence - clojure

I assume this is a very simple question, but I can't seem to find the answer online: how do you subtract n from every element of a Clojure sequence? E.g subtract 4 from each element of (6 9 11) and get (2 5 7)?
I assume this should be done with map, and I know that for the special case of subtracting 1 I can do (map dec (sequence)), but how do I do it for any other case?
For what it's worth, I figured out eventually that (map - (map (partial - n) (sequence)) technically does work, but it's clearly not how this is meant to be done.
For anyone who lands here from search and has a slightly different problem: if you want to subtract every element of a Clojure sequence from n, you can do that with (map (partial - n) (sequence))
Similarly, for multiplying every element of a Clojure sequence by n you can do (map (partial * n) (sequence))
For adding n to every element of a Clojure sequence (map (partial + n) (sequence))
I found that answer in these Clojure docs so I assume it's idiomatic, but obviously I'm not able to vouch for that myself.

An anonymous function literal is convenient here:
> (map #(- % 4) [6 9 11])
(2 5 7)
The #(- % 4) form is short-hand for the anonymous function in
> (map (fn [x] (- x 4)) [6 9 11])
(2 5 7)

If you're looking for a combinatory expression for the function you want, try (comp - (partial - 4)):
=> (map (comp - (partial - 4)) '(6 9 11))
(2 5 7)
Remember that + and - are just ordinary named Clojure functions. The function that you need is probably not worth naming, so you express it directly as #(- % 4) or (fn [n] (- n 4)), or as above.
It is also worth remembering that map is lazy, so can deal with endless sequences:
=> (take 10 (map (comp - (partial - 4)) (range)))
(-4 -3 -2 -1 0 1 2 3 4 5)

This can be achieved through maps. Clojure maps takes a function and list as an argument.
Synatax:
(map (function) (seq))
test=> (map (fn[arg] (- arg 4) ) '(7 8 9) )
(3 4 5)
test=> (map (fn[arg] (- arg 4) ) [7 8 9] )
(3 4 5)
Map can take function in shorthand notation too.
(- % 4)
. Here % is argument passed. Defaults to first argument. %1 to explicitly say first argument
test=> (map #(- %1 4) [7 8 9])
(3 4 5)
test=> (map #(- % 4) [7 8 9])
(3 4 5)

Related

Clojure: iterating on multiple (possibly infinite) sequences

I've got a couple of infinite sequences. I want to take one of each other per step. What's the idiomatic way of doing that? In other words, assume that there's a finite, realized sequence iss that contains lazy, infinite sequences. How to print out the first elements of every infinite sequence, then the second element of every infinite sequence, and so on?
I'd use a simple map vector. It returns a lazy sequence of applications of vector to the first elements of all the sequences, then the second elements and so on. Until you force realization, nothing get's mapped.
Try it for yourself (note that (range) returns an infinite lazy seq):
(def lazy-zipped (map vector (range) (drop 10 (range)) (drop 20 (range))))
(take 5 lazy-zipped)
prints
([0 10 20] [1 11 21] [2 12 22] [3 13 23] [4 14 24])
Maybe this?
user=> (def seq1 (iterate inc 1))
#'user/seq1
user=> (def seq2 (iterate inc 10))
#'user/seq2
user=> (take 10 (partition 2 (interleave seq1 seq2)))
((1 10) (2 11) (3 12) (4 13) (5 14) (6 15) (7 16) (8 17) (9 18) (10 19))

Map with an accumulator in Clojure?

I want to map over a sequence in order but want to carry an accumulator value forward, like in a reduce.
Example use case: Take a vector and return a running total, each value multiplied by two.
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
Which gives
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
Another example to illustrate the generality, print running sum as stars and the original number. A slightly convoluted example, but demonstrates that I need to keep the running accumulator in the map function:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
This works fine, but I would expect this to be a common pattern, and for some kind of map-with-accumulator to exist in core. Does it?
You should look into reductions. For this specific case:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
produces
(2 6 12 20 30)
The general solution
The common pattern of a mapping that can depend on both an item and the accumulating sum of a sequence is captured by the function
(defn map-sigma [f s] (map f s (sigma s)))
where
(def sigma (partial reductions +))
... returns the sequence of accumulating sums of a sequence:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
In the definition of map-sigma, f is a function of two arguments, the item followed by the accumulator.
The examples
In these terms, the first example can be expressed
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
In this case, the mapping function ignores the item and depends only on the accumulator.
The second can be expressed
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
... where the mapping function depends on both the item and the accumulator.
There is no standard function like map-sigma.
General conclusions
Just because a pattern of computation is common does not imply that
it merits or requires its own standard function.
Lazy sequences and the sequence library are powerful enough to tease
apart many problems into clear function compositions.
Rewritten to be specific to the question posed.
Edited to accommodate the changed second example.
Reductions is the way to go as Diego mentioned however to your specific problem the following works
(map #(* % (inc %)) [1 2 3 4 5])
As mentioned you could use reductions:
(defn map-with-accumulator [f init-value collection]
(map first (reductions (fn [[_ accumulator] next-elem]
(f next-elem accumulator))
(f (first collection) init-value)
(rest collection))))
=> (map-with-accumulator double-running-sum 0 [1 2 3 4 5])
(2 6 12 20 30)
=> (map-with-accumulator stars-sum 0 [1 2 3 4 5])
("*" "***" "******" "**********" "***************")
It's only in case you want to keep the original requirements. Otherwise I'd prefer to decompose f into two separate functions and use Thumbnail's approach.

repeatedly apply a function until test no longer yields true

I wrote this code to nest a function n times and am trying to extend the code to handle a test. Once the test returns nil the loop is stopped. The output be a vector containing elements that tested true. Is it simplest to add a while loop in this case? Here is a sample of what I've written:
(defn nester [a inter f]
(loop [level inter expr a]
(if (= level 0) expr
(if (> level 0) (recur (dec level) (f expr))))))
An example input would be an integer 2, and I want to nest the inc function until the output is great than 6. The output should be [2 3 4 5 6 7].
(defn nester [a inter f test-fn]
(loop [level inter
expr a]
(if (or (zero? level)
(nil? (test-fn expr)))
expr
(recur (dec level)
(f expr)))))
If you also accept false (additionally to nil) from your test-fn, you could compose this more lazily:
(defn nester [a inter f test-fn]
(->> (iterate f a)
(take (inc inter))
(drop-while test-fn)
first))
EDIT: The above was answered to your initial question. Now that you have specified completely changed the meaning of your question:
If you want to generate a vector of all iterations of a function f over a value n with a predicate p:
(defn nester [f n p]
(->> (iterate f n)
(take-while p)
vec))
(nester inc 2 (partial > 8)) ;; predicate "until the output is greater than six"
;; translated to "as long as 8 is greater than
;; the output"
=> [2 3 4 5 6 7]
To "nest" or iterate a function over a value, Clojure has the iterate function. For example, (iterate inc 2) can be thought of as an infinite lazy list [2, (inc 2), (inc (inc 2)), (inc (inc (inc 2))) ...] (I use the [] brackets not to denote a "list"--in fact, they represent a "vector" in Clojure terms--but to avoid confusion with () which can denote a data list or an s-expression that is supposed to be a function call--iterate does not return a vector). Of course, you probably don't want an infinite list, which is where the lazy part comes in. A lazy list will only give you what you ask it for. So if you ask for the first ten elements, that's what you get:
user> (take 10 (iterate inc 2))
> (2 3 4 5 6 7 8 9 10 11)
Of course, you could try to ask for the whole list, but be prepared to either restart your REPL, or dispatch in a separate thread, because this call will never end:
user> (iterate inc 2)
> (2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
=== Shutting down REPL ===
=== Starting new REPL at C:\Users\Omnomnomri\Clojure\user ===
Clojure 1.5.0
user>
Here, I'm using clooj, and this is what it looks like when I restart my REPL. Anyways, that's all just a tangent. The point is that iterate answers the core of your question. The other part, stopping upon some test condition, involves take-while. As you might imagine, take-while is a lot like take, only instead of stopping after some number of elements, it stops upon some test condition (or in Clojure parlance, a predicate):
user> (take-while #(< % 10) (iterate inc 2))
> (2 3 4 5 6 7 8 9)
Note that take-while is exclusive with its predicate test, so that here once the value fails the test (of being less than 10), it excludes that value, and only includes the previous values in the return result. At this point, solving your example is pretty straightfoward:
user> (take-while #(< % 7) (iterate inc 2))
> (2 3 4 5 6)
And if you need it to be a vector, wrap the whole thing in a call to vec:
user> (vec (take-while #(< % 7) (iterate inc 2)))
> [2 3 4 5 6]

clojure for sequence comprehnsion adding two elements at a time

The comprehension:
(for [i (range 5])] i)
... yields: (0 1 2 3 4)
Is there an idiomatic way to get (0 0 1 1 2 4 3 9 4 16) (i.e. the numbers and their squares) using mostly the for comprehension?
The only way I've found so far is doing a:
(apply concat (for [i (range 5)] (list i (* i i))))
Actually, using only for is pretty simple if you consider applying each function (identity and square) for each value.
(for [i (range 5), ; for every value
f [identity #(* % %)]] ; for every function
(f i)) ; apply the function to the value
; => (0 0 1 1 2 4 3 9 4 16)
Since for loops x times, it will return a collection of x values. Multiple nested loops (unless limited by while or when) will give x * y * z * ... results. That is why external concatenation will always be necessary.
A similar correlation between input and output exists with map. However, if multiple collections are given in map, the number of values in the returned collection is the size of the smallest collection parameter.
=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])
Concatenating the results of map is so common mapcat was created. Because of that, one might argue mapcat is a more idiomatic way over for loops.
=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)
Although this is just shorthand for apply concat (map, and a forcat function or macro could be created just as easily.
However, if an accumulation over a collection is needed, reduce is usually considered the most idiomatic.
=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]
Both the for and map options would mean traversing a collection twice, once for the range, and once for concatenating the resulting collection. The reduce option only traverses the range.
Care to share why "using mostly the for comprehension" is a requirement ?
I think you are doing it right.
A slightly compressed way maybe achieved using flatten
(flatten (for [i (range 5)] [ i (* i i) ] ))
But I would get rid of the for comprehension and just use interleave
(let [x (range 5)
y (map #(* % %) x)]
(interleave x y))
Disclaimer: I am just an amateur clojurist ;)

clojure map over sequence of pairs

(def tmp = [ 1 2 3 9 4 8])
I'm trying to create pairs of 2, then for each pair, subtract the second number from the first.
desired result: (1 6 4)
Here is what I was trying:
(map #(apply - %2 %1) (partition 2 tmp))
how can I do this?
Partition produces a sequence of sequences so the function you map over them needs to expect a sequence of two items. There are several ways to express this:
(def tmp [ 1 2 3 9 4 8])
user> (map #(- (second %) (first %)) (partition-all 2 tmp ))
(1 6 4)
user> (map #(apply - (reverse %)) (partition-all 2 tmp ))
(1 6 4)
user> (map (fn [[small large]] (- large small)) (partition-all 2 tmp ))
(1 6 4)
The version using apply is different because it will still "work" on odd length lists:
user> (map #(apply - (reverse %)) (partition-all 2 [1 2 3 4 5 6 7] ))
(1 1 1 -7)
The others will crash on invalid input, which you may prefer.
Here's a solution using reduce
(reduce #(conj %1 (apply - (reverse %2))) [] (partition-all 2 [1 2 3 9 4 8]))
=> [1 6 4]
I wonder why this solution was overlooked...
Since switching the order of subtraction is simply the negative of the original subtraction, (a-b=-(b-a)),
the solution becomes more efficient (only in this particular case!!)
(map #(- (apply - %)) (partition-all 2 [1 2 3 9 4 8]))
Pedagogically, Arthur's solution is correct. This is just a solution that is more suited the specfic question.