I have two collections x
and y
, both having different number of items. I want to loop through x
and do something with a side-effect, while cycling through y
. I don't want to repeat y
while looping through x
. Both doseq
and for
repeats y
:
(for [x (range 5)
y ["A" "B"]]
[x y])
This produces ([0 "A"] [0 "B"] [1 "A"] [1 "B"] [2 "A"] [2 "B"] [3 "A"] [3 "B"] [4 "A"] [4 "B"])
.
What I want is something that will produce: ([0 "A"] [1 "B"] [2 "A"] [3 "B"] [4 "A"])
.
Background, I have lines from a file and core.async
channels (say 5) and I want to put each line to the next channel in my collection, something like:
(defn load-data
[file chans]
(with-open [rdr (io/reader file)]
(go
(doseq [l (line-seq rdr)
ch chans]
(>! ch l)))))
If you pass multiple sequences to map
it steps through each of them in lock step calling the mapped function with the value from the current position in each. Stopping when one of the sequences runs out.
user> (map vector (range 5) (cycle ["A" "B"]))
([0 "A"] [1 "B"] [2 "A"] [3 "B"] [4 "A"])
In this case the sequence from (cycle ["A" "B"])
will keep producing As and Bs forever though map will stop consuming them when the sequence from (range 5)
ends. each step then calls the vector function with these two arguments and adds the result to the output sequence.
and for the second example using a go-loop is a fairly standard way of fanning out an input sequence:
user> (require '[clojure.core.async :refer [go go-loop <! <!! >!! >! chan close!]])
nil
user> (defn fanout [channels file-lines]
(go-loop [[ch & chans] (cycle channels)
[line & lines] file-lines]
(if line
(do
(>! ch line)
(recur chans lines))
(doseq [c channels]
(close! c)))))
#'user/fanout
user> (def lines ["first" "second" "third" "fourth" "fifth"])
#'user/lines
user> (def test-chans [(chan) (chan) (chan)])
#'user/test-chans
user> (fanout test-chans lines)
#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@3b363fc5>
user> (map <!! test-chans)
("first" "second" "third")
user> (map <!! test-chans)
("fourth" "fifth" nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With