Mohamed
Mohamed

Reputation: 87

Clojure - Idiomatic Way To Fill A Vector While In A Loop

I have a requirement where upon receipt of a request, I have to fetch values from an external source, filter them and return the filtered values to the caller. I am accumulating the result (until it reaches the required size) by fetching a specified amount of records from the external source at a time. I managed to come up with a solution, but I am not sure if it is the most elegant or idiomatic way of doing it.

Please see the simulated code below, where the the make-response function has to return the first 50 odd numbers to the caller. (Note that this code may not handle the edge cases, but I think is good enough for demonstration purpose).

Maybe I should use ref instead of atom? Thanks in advance for any suggestion.

(defn fetch [start]
  (let [end (+ start 10)]
    (range start end)))

(defn take-good-ones [all]
  (filter odd? all))

(defn make-response []
  (let [start (atom 0)
        result (atom [])]
    (while (< (count @result) 50)
      (do
       (let [all-values (fetch @start)
             good-values (take-good-ones all-values)
             handled-this-time (count all-values)]
         (swap! start + handled-this-time)
         (swap! result concat good-values))))
   @result))

Upvotes: 1

Views: 478

Answers (2)

Thumbnail
Thumbnail

Reputation: 13473

Further to Joost's answer, the batches are each filtered then concatenated, so the batching has no effect. So the effect is just

(defn make-response []
  (->> (range) (filter odd?) (take 50)))

Upvotes: 0

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17773

No need for mutating atoms or low-level looping stuff:

; the next 10 items since start
(defn fetch [start] 
   (range start (+ 10 start)))

; lazy sequence of good values, by getting batches of 10 from `fetch`
(defn all-good-values [] 
   (filter odd? 
      (mapcat #(fetch (* 10 %)) (range))))

(defn make-response [] 
   (take 20 (all-good-values)))

(make-response) => (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39)

Upvotes: 4

Related Questions