做的时候
(map f [0 1 2] [:0 :1])
f
将被调用两次,参数为
是否有一种简单而有效的方法,即不产生更多的中间序列等,以便使用以下参数为第一个集合的每个值调用f
?
编辑在评论中通过@ fl00r解决问题。
触发此问题的实际用例需要map始终正好(count first-coll)
次,无论第二个(或第三个或......)集合是否更长。
现在游戏有点晚了,在接受了答案之后有些不公平,但是如果添加一个好的答案只能做我特别要求的 - 映射(count first-coll)
次 - 我会接受。 / p>
答案 0 :(得分:5)
你可以这样做:
(map f [0 1 2] (concat [:0 :1] (repeat nil)))
基本上,用无限的nils序列填充第二个coll。 map
在到达第一个集合的末尾时停止。
一个(急切的)循环/重复形式,走向最长的一端:
(loop [c1 [0 1 2] c2 [:0 :1] o []]
(if (or (seq c1) (seq c2))
(recur (rest c1) (rest c2) (conj o (f (first c1) (first c2))))
o))
或者你可以写一个懒惰的地图版本做类似的事情。
答案 1 :(得分:1)
Alex Miller's answer建议的一般懒惰版本是
(defn map-all [f & colls]
(lazy-seq
(when-not (not-any? seq colls)
(cons
(apply f (map first colls))
(apply map-all f (map rest colls))))))
例如,
(map-all vector [0 1 2] [:0 :1])
;([0 :0] [1 :1] [2 nil])
您可能希望为一个和两个集合专门化map-all
。
答案 2 :(得分:0)
只是为了好玩
这可以通过常见的lisp的do
宏轻松完成。我们可以用clojure实现它,并用它来做这个(以及更多有趣的事情):
(defmacro cl-do [clauses [end-check result] & body]
(let [clauses (map #(if (coll? %) % (list %)) clauses)
bindings (mapcat (juxt first second) clauses)
nexts (map #(nth % 2 (first %)) clauses)]
`(loop [~@bindings]
(if ~end-check
~result
(do
~@body
(recur ~@nexts))))))
然后只使用它进行映射(注意它可以在2个以上的colls上运行):
(defn map-all [f & colls]
(cl-do ((colls colls (map next colls))
(res [] (conj res (apply f (map first colls)))))
((every? empty? colls) res)))
在repl中:
user> (map-all vector [1 2 3] [:a :s] '[z x c v])
;;=> [[1 :a z] [2 :s x] [3 nil c] [nil nil v]]