Clojure:如何根据索引合并地图向量?
Clojure: How to merge vector of maps on the basis of index?
我正在尝试合并地图矢量。
我尝试使用 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)))
代码片段使其更加清晰和精简。
非常感谢所有帮助我达到这一点的答案。
(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
一般情况下,你可以只使用map
和merge
来合并hashmap的集合,但是当其中一个集合用完时它会结束合并。
您可以创建如下函数来 "extend" 集合具有相同的长度,然后像往常一样合并:
(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”集合,例如 (range)
).
我会把它分解成多个简单的步骤,如下所示:
(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"}] ) )
您也可以用 nils 填充较短的序列,然后使用 (map merge ...)
,但您必须确保首先获得正确的长度,这仍然涉及 count
和 max
...不确定这是否更简单。
我正在尝试合并地图矢量。
我尝试使用 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)))
代码片段使其更加清晰和精简。 非常感谢所有帮助我达到这一点的答案。
(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
一般情况下,你可以只使用map
和merge
来合并hashmap的集合,但是当其中一个集合用完时它会结束合并。
您可以创建如下函数来 "extend" 集合具有相同的长度,然后像往常一样合并:
(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”集合,例如 (range)
).
我会把它分解成多个简单的步骤,如下所示:
(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"}] ) )
您也可以用 nils 填充较短的序列,然后使用 (map merge ...)
,但您必须确保首先获得正确的长度,这仍然涉及 count
和 max
...不确定这是否更简单。