Reputation: 87
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
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
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