Iterate over a list with a given step in clojure

Viewed 320

I'm trying to iterate over a list with a given step in clojure.

In python I would have done the following :

xs = list(range(10))

xs[::2]
# out: [0, 2, 4, 6, 8]

xs[1::2]
# out: [1, 3, 5, 7, 9]

I can't figure out a clojure solution that feels idiomatic.

Here is the best I can think of:

(defn iterate-step-2 [xs]
  (map first (take-while some? (iterate nnext xs))))

(iterate-step-2 (range 10))
; out: (0 2 4 6 8)

(iterate-step-2 (rest (range 10)))
; out: (1 3 5 7 9)

But it's not as generic (step is not configurable) and as flexible as the python solution. Plus it seems overly complicated.

Is there a better way to do this ?

3 Answers

You can use take-nth for this:

user=> (take-nth 2 (range 10))
(0 2 4 6 8)
user=> (take-nth 2 (rest (range 10)))
(1 3 5 7 9)
;; equivalent to Python's your_seq[1:7:2] would be:
(->> your-seq (drop 1) (take 7) (take-nth 2))

;; equivalent to Python's your_seq[::2] would be:
(->> your-seq (take-nth 2))

;; equivalent to Python's your_seq[2:4:-3] would be:
(->> your-seq (take 4) (drop 2) (reverse) (take-nth 3))

;; equivalent to Python's your_seq[2:-4:-1]:
(->> your-seq (take (+ 1 (- (length your-seq) 4))) (drop 2) (reverse))

Another option is to generate the desired index values, and then use those for the lookup:

  (let [N      10
        data   (vec (range N)) ; `vec` is optional but faster than using (lazy) list if large N
        idxs   (range 1 10 2)
        result (mapv #(nth data %) idxs)]
    )

with result:

N       => 10
data    => [0 1 2 3 4 5 6 7 8 9]
idxs    => (1 3 5 7 9)
result  => [1 3 5 7 9]

or something less simple:

  (let [N      9999
        data   (vec (range N)) ; `vec` is optional but faster than using (lazy) list if large N
        idxs   (mapv #(Math/pow 2 %) (range 11))
        result (mapv #(nth data %) idxs)]

with result:

idxs => [1.0 2.0 4.0 8.0 16.0 32.0 64.0 128.0 256.0 512.0 1024.0]
result => [1 2 4 8 16 32 64 128 256 512 1024]

Interesting! Apparently nth will accept a floating-point index value as long as it has a zero fraction. :)

Related