如何在循环 Clojure 中的第一个集合时合并两个集合的元素?

How do I merge the elements of two collections while cycling the first in Clojure?

如何优雅地接受这两个输入:

(def foo [:a 1 :a 1 :a 2])

(def bar [{:hi "there 1"}{:hi "there 2"}{:hi "there 3"}{:hi "there 4"}{:h1 "there 5"}])

并得到:

[{:hi "there 1" :a 1}{:hi "there 2" :a 1}{:hi "there 3" :a 2}{:hi "there 4" :a 1}{:hi "there 5" :a 1}]

第一次收集在第二次收集达到相同数量的元素时循环。第一个集合可以是这些中的任何一个,因为它将被硬编码:

(def foo [{:a 1} {:a 1} {:a 2}])

(def foo [[:a 1] [:a 1] [:a 2]])

(def foo [1 1 2])

可能还有另一种数据结构会更好。 1 1 2 是故意的,因为它不是 1 2 3 允许 range 或类似的东西。

循环浏览第一个集合很容易...我不确定如何同时浏览第二个集合。但我的做法可能一开始就不对。

像往常一样,我倾向于对命令式代码进行奇怪的嵌套模仿,但我知道有更好的方法!

这是一种方法:

您可以从 foo 中获取值,循环遍历它们并将它们一次分成 2 组。大小为 2 的向量有一个小秘密,那就是它们可以用作小地图(1 key/value 对)。

一旦我们有了两个地图集,我们就可以将它们合并在一起。一个集合是无限的,但没关系,map 将只计算值,直到一个集合用完所有元素。 mapvmap 相同,但它 returns 是一个向量。

(def foo [:a 1 :a 1 :a 2])

(def bar [{:hi "there 1"}{:hi "there 2"}{:hi "there 3"}{:hi "there 4"}{:h1 "there 5"}])

(defn cycle-and-zip [xs maps]
  (let [xs-pairs (->> xs cycle (partition 2) (map vec))]
    (mapv merge maps xs-pairs)))

(cycle-and-zip foo bar)
;; => [{:hi "there 1", :a 1} {:hi "there 2", :a 1} {:hi "there 3", :a 2} {:hi "there 4", :a 1} {:h1 "there 5", :a 1}]

更新:将 map 替换为 mapv,因此输出实际上是一个向量。

(def foo [{:a 1} {:a 1} {:a 2}])
(def bar [{:hi "there 1"}{:hi "there 2"}{:hi "there 3"}{:hi "there 4"}{:h1 "there 5"}])

(mapv merge (cycle foo) bar)