我正在尝试合并地图矢量。
我尝试使用reduce
方法执行此操作,但是无法检索预期的结果。
(def data '([{:padding-top "30px"} {:padding-top "40px"} {:padding-top "50px"}] [{:margin "40px"}]))
(reduce #(hash-map %1 %2) () data)
输入数据:
(def data '([{:padding-top "30px"} {:padding-top "40px"} {:padding-top "50px"}] [{:margin "40px"}]))
(defn merge-data
[data]
)
预期输出:
(merge-data data)
({:padding-top "30px" :margin "40px"}
{:padding-top "40px"}
{:padding-top "50px"})
从JS的背景来看,我可以使用forEach和有条件的条件轻松构建预期的输出。但是如何以功能方式做到这一点?
解决方案:
我能够通过以下方式解决此问题
(defn merge-styles
[& args]
(let [max-count (apply max (map #(count %1) args))
items (map #(take max-count (concat %1 (repeat nil))) args)]
(apply map merge items)))
该代码段使其更清晰,更精简。 非常感谢所有帮助我起步的答案。
答案 0 :(得分:1)
通常,您可以仅使用map
和merge
来合并哈希图集合,但是当其中一个集合耗尽时,它将结束合并。
您可以创建如下所示的函数来“扩展”集合以使其具有相同的长度,然后照常进行合并:
(defn merge-all
"Merges two sequences of maps using merge. Consumes all entries."
[xs ys]
(let [n (max (count xs) (count ys))
xs (take n (concat xs (repeat nil)))
ys (take n (concat ys (repeat nil)))]
(map merge xs ys)))
(def data [[{:padding-top "30px"} {:padding-top "40px"} {:padding-top "50px"}]
[{:margin "40px"}]])
;; (apply merge-all data)
;; => ({:padding-top "30px", :margin "40px"} {:padding-top "40px"} {:padding-top "50px"})
请注意,在您的示例中,您在data
周围使用了括号,但是在Clojure中,这意味着您希望像调用函数一样调用它。在上面的示例中,我将其切换为[
和]
。另外,请注意,此功能取决于您实际上可以count
传递给它的集合(在Clojure中,您可以拥有“ infinite ”集合,例如{{1} }。
答案 1 :(得分:0)
(map into [{:a 1} {:c 3}] (concat [{:b 2}] (repeat nil)))
产量
({:a 1, :b 2} {:c 3})
。
map
从两个向量中读取并将各自的索引应用于into
,合并每个索引的映射。当其中一个集合用完时map
停止时,我们需要将nil
的值连接到较短的集合。
编辑:与往常一样,此问题之前已经得到解答:Using 'map' with different sized collections in clojure
答案 2 :(得分:0)
我会将其分解为多个简单的步骤,如下所示:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def data [[{:padding-top "30px"} {:padding-top "40px"} {:padding-top "50px"}]
[{:margin "40px"}]])
; be clear about the 2 sequences we are combining
(def data-1 (first data))
(def data-2 (second data))
(defn do-merge []
(let [N (max (count data-1) (count data-2))]
(vec (for [i (range N)]
(let [map-1 (get data-1 i)
map-2 (get data-2 i)] ; returns `nil` if no value present
(merge map-1 map-2) ; if merge a map & nil, it's a noop
)))))
(dotest
(is= (do-merge)
[{:padding-top "30px", :margin "40px"}
{:padding-top "40px"}
{:padding-top "50px"}] ) )
您也可以使用nil填充较短的序列,然后使用(map merge ...)
,但是您必须确保首先获得正确的长度,而这些长度仍然涉及count
和max
....不确定那是否更简单。