简体   繁体   English

Clojure:循环浏览一个集合,同时循环浏览另一个集合?

[英]Clojure: Cycle through a collection while looping through another collection?

I have two collections x and y , both having different number of items. 我有两个集合xy ,两个都有不同的项目数。 I want to loop through x and do something with a side-effect, while cycling through y . 我想循环通过x并做一些副作用,同时循环通过y I don't want to repeat y while looping through x . 我不想在循环x重复y Both doseq and for repeats y : 无论doseqfor重复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"]) . 这产生([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"]) . 我想要的是会产生的东西: ([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: 背景,我有来自文件和core.async频道的行(比如5),我想把每一行放到我的集合中的下一个频道,如:

(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. 如果您传递多个序列进行map则会在锁定步骤中逐步执行每个序列,并使用每个序列中的当前位置调用映射函数。 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. 在这种情况下,来自(cycle ["A" "B"])的序列将永远产生As和Bs,尽管当(range 5)的序列结束时,map将停止消耗它们。 each step then calls the vector function with these two arguments and adds the result to the output sequence. 然后,每一步都使用这两个参数调用vector函数,并将结果添加到输出序列中。

and for the second example using a go-loop is a fairly standard way of fanning out an input sequence: 对于第二个使用go-loop的例子是一个相当标准的扇出输入序列的方法:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM