2015-03-13 72 views
3

我有两个系列xy,都有不同数量的项目。我想通过x循环,并做一些副作用,而通过y骑自行车。我不想在通过x循环时重复y。既doseqfor重复yClojure:在循环另一个集合的同时循环一个集合?

(for [x (range 5) 
     y ["A" "B"]] 
    [x y]) 

这产生([0 "A"] [0 "B"] [1 "A"] [1 "B"] [2 "A"] [2 "B"] [3 "A"] [3 "B"] [4 "A"] [4 "B"])

我想要的是会产生的东西:([0 "A"] [1 "B"] [2 "A"] [3 "B"] [4 "A"])

背景,我有一个文件行和core.async渠道(比如5),我希望把每行到下一个通道在我的收藏,是这样的:

(defn load-data 
    [file chans] 
    (with-open [rdr (io/reader file)] 
    (go 
     (doseq [l (line-seq rdr) 
       ch chans] 
     (>! ch l))))) 

回答

7

如果传递到多个序列map它在锁步骤中逐步通过它们中的每一个来调用具有来自每个当前位置的值的映射函数。当其中一个序列用完时停止。

user> (map vector (range 5) (cycle ["A" "B"])) 
([0 "A"] [1 "B"] [2 "A"] [3 "B"] [4 "A"]) 

在这种情况下,从(cycle ["A" "B"])序列将继续生产As和烧烤永远虽然地图会停止食用它们(range 5)结束序列时。每一步然后用这两个参数调用向量函数,并将结果添加到输出序列中。

和第二例使用去环是散开的输入序列的一个相当标准的方法:

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 [email protected]> 
user> (map <!! test-chans) 
("first" "second" "third") 
user> (map <!! test-chans) 
("fourth" "fifth" nil) 
+0

因此,我将不得不采取的这个结果,然后doseq在它把它放入渠道? – arnab 2015-03-13 17:09:41

+0

是的。我个人认为,我喜欢将数据生成保存在自己的函数中,这样我就可以独立于移动它的机制来进行测试。 – 2015-03-13 17:11:37

+0

是的,最终我想保持我所有的功能都是纯粹的,并且有一层可以管理频道推送和拉取的功能,所以这是有效的。 – arnab 2015-03-13 17:13:22