【问题标题】:Using 'map' with different sized collections in clojure在 clojure 中使用具有不同大小集合的'map'
【发布时间】:2013-09-27 06:00:16
【问题描述】:
我想了解在 clojure 中对不同大小的集合进行操作的惯用方式。有没有办法告诉函数'map'用一些默认值填充集合的其余部分?
例如,假设我有 3 个向量:
(def x [1 2 3 4])
(def y [1 2 3 4 5])
(def z [1 2 3 4 5 6 7])
(map + x y z) ; yields (3 6 9 12)
在这种情况下,我如何用零填充 x 和 y 并获得这个收益:
(3 6 9 12 10 6 7)
【问题讨论】:
标签:
collections
map
clojure
functional-programming
【解决方案1】:
map 不会自己做,但是你可以使用concat 和repeat 的组合来获得想要的结果:
(def x [1 2 3 4])
(def y [1 2 3 4 5])
(def z [1 2 3 4 5 6 7])
(map +
(concat x (repeat 0))
(concat y (repeat 0))
z) ; => (3 6 9 12 10 6 7)
这是concat 和repeat 的 API 文档。
这里有一个关于如何将其抽象出来的草图,因此您无需知道哪个集合最长。 (在上面的sn-p中,如果你concat所有的集合到(repeat 0)你会有一个无限序列)。
(defn map-longest
[f default & colls]
(lazy-seq
(when (some seq colls)
(cons
(apply f (map #(if (seq %) (first %) default) colls))
(apply map-longest f default (map rest colls))))))
(map-longest +
0
[1 2 3 4]
[1 2 3 4 5]
[1 2 3 4 5 6 7]) ; => (3 6 9 12 10 6 7)
您可以看到其他几种方法作为this previous question on Stack Overflow 的答案。
【解决方案2】:
您可以通过以下函数合并可变长度的地图矢量:
(defn merge-maps
[& args]
(let [max-count (apply max (map #(count %1) args))
items (map #(take max-count (concat %1 (repeat nil))) args)]
(apply map merge items)))
这个函数使解更加泛化,可以取任意长度的地图向量。