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)
Related
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)
Clojure's map is what other lisps might call mapcar with car being roughly equivalent to clojure's first. This makes me wonder if there is a mapcdr and whether clojure has a such a function where cdr is roughly equivalent to clojure's rest.
I imagine the behavior to be like such:
(mapcdr #(apply + %) [1 2 3 4 5])
=> (15 14 12 9 5)
The expansion looking like:
(list (apply + [1 2 3 4 5])
(apply + [2 3 4 5])
(apply + [3 4 5])
(apply + [4 5])
(apply + [5])
You can use the fn reductions, which does almost what you want:
(->> [1 2 3 4 5]
reverse
(reductions +)
reverse)
Wrote something quick, though it'd still be nice to have something more native.
(defn maplist
"Based on Common Lisp's maplist."
[fn coll]
(if (empty? coll) nil
(cons (fn coll)
(maplist fn (rest coll)))))
(maplist #(apply + %) [1 2 3 4 5])
=> (15 14 12 9 5)
I'd be surprised if there isn't because it seems like standard map is just maplist with first wrapped around coll.
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))
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.
Does the Clojure library have a "drop-every" type function? Something that takes a lazy list and returns a list with every nth item dropped?
Can't quite work out how to make this.
cheers
Phil
(defn drop-every [n xs]
(lazy-seq
(if (seq xs)
(concat (take (dec n) xs)
(drop-every n (drop n xs))))))
Example:
(drop-every 2 [0 1 2 3 4 5])
;= (0 2 4)
(drop-every 3 [0 1 2 3 4 5 6 7 8])
;= (0 1 3 4 6 7)
As a side note, drop-nth would be a tempting name, as there is already a take-nth in clojure.core. However, take-nth always returns the first item and then every nth item after that, whereas the above version of drop-every drops every nth item beginning with the nth item of the original sequence. (A function dropping the first item and every nth item after the first would be straightforward to write in terms of the above.)
If the input list length is a multiple of n you can use the partition function:
(defn drop-every [n lst] (apply concat (map butlast (partition n lst))))
(take 5 (drop-every 3 (range)))
; (0 1 3 4 6)