Clojure: iterating on multiple (possibly infinite) sequences - clojure

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))

Related

Subtract n from every element of a Clojure sequence

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)

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 - Splitting a sequence into multiple sequences

I am working on a function that will split a sequence of dates (or anything else) into a number of sequences contained within a vector based on a given number x.
(date1 date2 date3 date4 date5 date6 date7)
So given the list of dates above and passing in the variable 2 it will produce the vector below.
[(date1 date2) (date3 date4) (date5 date6) (date7)]
The code I have so far is below but all it returns is a vector containing nil.
(defn date-splitter [date-count dates x]
(loop [i date-count, current-split dates, split-dates (vector)]
(if (<= i x)
(conj split-dates (get current-split 1))
(let [s (split-at x current-split)]
(recur (int (- i x)) (get s 1) (conj split-dates (get s 0)))))))
I have also had a look at the split-with function, thinking that I could use it to split the sequence when the modulus of the index divided by x is zero, but I haven't had any luck with this.
Any help would be greatly appreciated.
David.
Take a look at split's cousin partition
=> (partition-all 2 '(1 2 3 4 5 6 7))
((1 2) (3 4) (5 6) (7))
If you want to do index based operations, you can use map-indexed and keep-indexed.
=> (map-indexed (fn [idx itm] [(Math/floor (/ idx 2)) itm]) [1 2 3 4 5 6 7])
([0.0 1] [0.0 2] [1.0 3] [1.0 4] [2.0 5] [2.0 6] [3.0 7])
In FP, non-index based operations are usually the better option though.
Index based solutions can be considered code smell.
There's several ways of doing partition the FP way without index. Ankur's is a great example of how to solve this if partition-all wouldn't have been in core clojure.
(defn date-splitter [n v]
(if (not (seq v))
[]
(lazy-cat [(take n v)] (date-splitter n (drop n v)))))
user=> (date-splitter 3 [1,2,3,4])
((1 2 3) (4))

processing a seq until a pred function is true

I am processing a sequence in clojure. I would like to retrieve elements until a predicate function is true. How do I do that?
You can use take-while along with not
user=> (take-while (comp not even?) [3 9 2 4 6 10 1 2])
(3 9)