【问题标题】:Clojure: Cycle through a collection while looping through another collection?Clojure:循环通过一个集合,同时循环通过另一个集合?
【发布时间】:2015-03-13 16:49:35
【问题描述】:

我有两个集合 xy,它们都有不同数量的项目。我想循环通过x 并做一些有副作用的事情,同时循环通过y。我不想在循环通过x 时重复ydoseqfor 都重复 y

(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)))))

【问题讨论】:

    标签: clojure core.async


    【解决方案1】:

    如果您将多个序列传递给map,它会在锁定步骤中逐步遍历每个序列,并使用每个序列中当前位置的值调用映射函数。当其中一个序列用完时停止。

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

    在这种情况下,来自(cycle ["A" "B"]) 的序列将永远产生 As 和 B,尽管当来自 (range 5) 的序列结束时 map 将停止使用它们。然后每个步骤都使用这两个参数调用向量函数,并将结果添加到输出序列中。

    对于第二个示例,使用 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)
    

    【讨论】:

    • 那么,我必须得到结果,然后对它进行doseq 将其放入通道中?
    • 是的。在我个人看来,我喜欢将数据生成保留在它自己的功能中,这样我就可以独立于移动它的机制来测试它。
    • 是的,最终我想保持我所有的函数的纯净,并在它上面有一个层来管理通道的推送和拉取,所以这是可行的。
    • 请记住,您不能将通道操作&lt;! 等放入映射函数中,因为 go 块不能跨越函数边界
    • 嗯,对。此外,如果您查看我的实际示例,这些行将来自调用(line-seq rdr),就像在这里一样,我们将所有数据都放在一个值中。回到绘图板:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    • 2019-09-16
    • 2018-06-20
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    • 2014-06-29
    相关资源
    最近更新 更多