Hendekagon
Hendekagon

Reputation: 4643

Neat way to apply a function to every nth element of a sequence?

What's a neat way to map a function to every nth element in a sequence ? Something like (map-every-nth fn coll n), so that it would return the original sequence with only every nth element transformed, e.g. (map-every-nth inc (range 16) 4) would return (0 1 2 4 4 5 6 8 8 9 10 12 12 13 14 16)

Upvotes: 7

Views: 3166

Answers (3)

Jason
Jason

Reputation: 12283

I personally like this solution better:

(defn apply-to-last [f col] (concat (butlast col) (list (f (last col)))))
(apply concat (map #(apply-to-last (fn [x] (* 2 x)) %) (partition 4 (range 16))))

Or as a function:

(defn apply-to-last [f col] (concat (butlast col) (list (f (last col)))))
(defn map-every-nth [f col n] (apply concat (map #(apply-to-last f %) (partition n col))))
(map-every-nth (fn [x] (* 2 (inc x))) (range 16) 4)
; output: (0 1 2 8 4 5 6 16 8 9 10 24 12 13 14 32)

Notice this easily leads to the ability to apply-to-first, apply-to-second or apply-to-third giving the ability to control the "start" of mapping every nth element.

I do not know the performance of the code I wrote above, but it does seem more idiomatic to me.

Upvotes: 0

Alex D
Alex D

Reputation: 30445

I suggest that this would be simpler and cleaner than the accepted answer:

(defn map-every-nth [f coll n]
  (map f (take-nth n coll)))

This is a handy one to know: http://clojuredocs.org/clojure_core/clojure.core/take-nth

Upvotes: 1

Óscar López
Óscar López

Reputation: 236004

Try this:

(defn map-every-nth [f coll n]
  (map-indexed #(if (zero? (mod (inc %1) n)) (f %2) %2) coll))

(map-every-nth inc (range 16) 4)
> (0 1 2 4 4 5 6 8 8 9 10 12 12 13 14 16)

Upvotes: 13

Related Questions