在Clojure中特定范围内的映射列表中填写缺少的值

在Clojure中特定范围内的映射列表中填写缺少的值,clojure,Clojure,如果我们的输入看起来像这样: (({:a 1 :b 100} {:a 2 :b 300} {:a 4 :b 0}) ({:a 0 :b 10} {:a 4 :b 50})) 我们希望监控的范围是(01 2 3 4) ​ 我们希望输出为: (({:a 0 :b 0} {:a 1 :b 100} {:a 2 :b 300} {:a 3 :b 0} {:a 4 :b 0}) ({:a 0 :b 10} {:a 1 :b 0} {:a 2 :b 0} {:a 3 :b 0} {:a 4 :b

如果我们的输入看起来像这样:

 (({:a 1 :b 100} {:a 2 :b 300} {:a 4 :b 0}) ({:a 0 :b 10} {:a 4 :b 50}))
我们希望监控的范围是
(01 2 3 4)
​ 我们希望输出为:

 (({:a 0 :b 0} {:a 1 :b 100} {:a 2 :b 300} {:a 3 :b 0} {:a 4 :b 0}) 
 ({:a 0 :b 10} {:a 1 :b 0} {:a 2 :b 0} {:a 3 :b 0} {:a 4 :b 50}))
基本上,它应该做的是查看第一个地图列表,然后查看第二个地图列表,依此类推,并找出
:a
的范围。我们可以使用min/max函数轻松实现这一点。现在它创建一个范围并将其应用于两个列表。如果一个列表中缺少一个
:a
,它会在该
:a
中添加
:b
0
。(即在第一个列表中添加了
{:a0:b0}
{:a3:b0}
。我们有一个函数可以实现这一点,但还没有完全实现。下面是:

 (map 
    #(doseq [i (vec myRange)] 
        (if (some (fn [list] (= i list)) (map :a %)) 
            nil 
            (println (conj % {:a i :b 0}))))
     myList)
显然,由于Clojures不可变的数据结构,此函数失败。如果我们的输入类似于:

 (({:a 1, :b 1} {:a 2, :b 3} {:a 4, :b 5}) 
  ({:a 0, :b 3} {:a 4, :b 1}))
我们的产出是:

 (nil nil)
但如果我们打印出:

 ({:a 0, :b 0} {:a 1, :b 1} {:a 2, :b 3} {:a 4, :b 5})
 ({:a 3, :b 0} {:a 1, :b 1} {:a 2, :b 3} {:a 4, :b 5})
 ({:a 1, :b 0} {:a 0, :b 3} {:a 4, :b 1})
 ({:a 2, :b 0} {:a 0, :b 3} {:a 4, :b 1})
 ({:a 3, :b 0} {:a 0, :b 3} {:a 4, :b 1})
 (nil nil) 
我们希望输出如下所示:

(({:a 0, :b 0} {:a 1, :b 1} {:a 2, :b 3} {:a 3, :b 0} {:a 4, :b 5})
 ({:a 0, :b 3} {:a 1, :b 0} {:a 2, :b 0} {:a 3, :b 0} {:a 4, :b 1}))

没有使用println。有什么建议吗?

在循环中使用不可变数据的想法是将最新迭代的结果传递给下一个迭代。您可以使用
循环/recur
,但在您的情况下,通常使用
reduce
函数(这实际上是函数式编程的基石之一):

reduce
的第一个参数为范围(
i
)的每个值“更新”
项,将更新后的值传递给下一次迭代

现在,您只需将输入数据映射到它:

(def input '(({:a 1 :b 100} {:a 2 :b 300} {:a 4 :b 0})
             ({:a 0 :b 10} {:a 4 :b 50})))

(map (comp (partial sort-by :a) 
           (partial update-coll [0 1 2 3 4])) 
     input)
输出:

(({:a 0, :b 0} {:a 1, :b 100} {:a 2, :b 300} 
  {:a 3, :b 0} {:a 4, :b 0}) 
 ({:a 0, :b 10} {:a 1, :b 0} {:a 2, :b 0} 
  {:a 3, :b 0} {:a 4, :b 50})) 
(#{{:b 0, :a 0} {:a 1, :b 100} {:a 2, :b 300} 
   {:b 0, :a 3} {:a 4, :b 0}} 
 #{{:a 0, :b 10} {:b 0, :a 1} {:b 0, :a 2} 
   {:b 0, :a 3} {:a 4, :b 50}})
此外,您还可以使用clojure的集合进行无累积:

(defn process-input [input r]
  (let [r (map #(hash-map :a % :b 0) r)]
    (map (fn [items] (into (apply sorted-set-by
                                  #(compare (:a %1) (:a %2))
                                  items)
                           r))
         input)))

(process-input input [0 1 2 3 4])
输出:

(({:a 0, :b 0} {:a 1, :b 100} {:a 2, :b 300} 
  {:a 3, :b 0} {:a 4, :b 0}) 
 ({:a 0, :b 10} {:a 1, :b 0} {:a 2, :b 0} 
  {:a 3, :b 0} {:a 4, :b 50})) 
(#{{:b 0, :a 0} {:a 1, :b 100} {:a 2, :b 300} 
   {:b 0, :a 3} {:a 4, :b 0}} 
 #{{:a 0, :b 10} {:b 0, :a 1} {:b 0, :a 2} 
   {:b 0, :a 3} {:a 4, :b 50}})

在循环中使用不可变数据的想法是将最新迭代的结果传递给下一个迭代。您可以使用
循环/recur
,但在您的情况下,通常使用
reduce
函数(这实际上是函数式编程的基石之一):

reduce
的第一个参数为范围(
i
)的每个值“更新”
项,将更新后的值传递给下一次迭代

现在,您只需将输入数据映射到它:

(def input '(({:a 1 :b 100} {:a 2 :b 300} {:a 4 :b 0})
             ({:a 0 :b 10} {:a 4 :b 50})))

(map (comp (partial sort-by :a) 
           (partial update-coll [0 1 2 3 4])) 
     input)
输出:

(({:a 0, :b 0} {:a 1, :b 100} {:a 2, :b 300} 
  {:a 3, :b 0} {:a 4, :b 0}) 
 ({:a 0, :b 10} {:a 1, :b 0} {:a 2, :b 0} 
  {:a 3, :b 0} {:a 4, :b 50})) 
(#{{:b 0, :a 0} {:a 1, :b 100} {:a 2, :b 300} 
   {:b 0, :a 3} {:a 4, :b 0}} 
 #{{:a 0, :b 10} {:b 0, :a 1} {:b 0, :a 2} 
   {:b 0, :a 3} {:a 4, :b 50}})
此外,您还可以使用clojure的集合进行无累积:

(defn process-input [input r]
  (let [r (map #(hash-map :a % :b 0) r)]
    (map (fn [items] (into (apply sorted-set-by
                                  #(compare (:a %1) (:a %2))
                                  items)
                           r))
         input)))

(process-input input [0 1 2 3 4])
输出:

(({:a 0, :b 0} {:a 1, :b 100} {:a 2, :b 300} 
  {:a 3, :b 0} {:a 4, :b 0}) 
 ({:a 0, :b 10} {:a 1, :b 0} {:a 2, :b 0} 
  {:a 3, :b 0} {:a 4, :b 50})) 
(#{{:b 0, :a 0} {:a 1, :b 100} {:a 2, :b 300} 
   {:b 0, :a 3} {:a 4, :b 0}} 
 #{{:a 0, :b 10} {:b 0, :a 1} {:b 0, :a 2} 
   {:b 0, :a 3} {:a 4, :b 50}})
我的尝试:

(defn fill-in-missing [lists]
  (let [[min max] (apply (juxt min max) (map :a (flatten lists)))]
    (for [cur-list lists]
      (for [i (range min (inc max))]
        (merge {:a i :b 0} 
               (some #(when (= i (:a %)) %) cur-list))))))
为了得到
:a
的最小值和最大值,我只需使用
map
收集每个
:a
,然后使用,这样我就可以
同时对它们应用
min
max
函数。
因为我们需要两个级别的嵌套列表,所以我选择了两个列表理解,并尝试创建一个表达式,尝试在输入中查找映射,或者返回默认的
{:ai:b0}

我的尝试:

(defn fill-in-missing [lists]
  (let [[min max] (apply (juxt min max) (map :a (flatten lists)))]
    (for [cur-list lists]
      (for [i (range min (inc max))]
        (merge {:a i :b 0} 
               (some #(when (= i (:a %)) %) cur-list))))))
为了得到
:a
的最小值和最大值,我只需使用
map
收集每个
:a
,然后使用,这样我就可以
同时对它们应用
min
max
函数。

因为我们需要两级嵌套列表,所以我选择了两个列表理解,并尝试创建一个表达式,尝试在输入中查找映射,或者返回默认的
{:ai:b0}

哇,非常感谢您的深入描述!哇,非常感谢您的深入描述!