简体   繁体   English

如何使用assoc-in更新地图中的多个值? (Clojure的)

[英]How to use assoc-in to update multiple values in a map? (Clojure)

I am trying to update every line that has an "enjoy-clojure?" 我正在尝试更新每个有“享受 - 乐趣”的行吗? that returns true "sanity-rating" to -2 (ie johnny's sanity-rating would be updated to -2) 将真正的“理智等级”返回到-2(即约翰尼的理智等级将更新为-2)

(def student-database
  { 0 {:enjoy-clojure? false, :name "jimmy",:sanity-rating 9}
    1 { :enjoy-clojure? true, :name "johnny",:sanity-rating 2}
    2 { :enjoy-clojure? true, :name "jilly",:sanity-rating 5}
    3 { :enjoy-clojure? true, :name "janey",:sanity-rating 8}
    4 {:enjoy-clojure? false, :name "jelly",:sanity-rating 10}}) 

I am new to Clojure and have tried researching update and assoc and can't really seem to find a way to update multiple elements ( (assoc student-database [0 :sanity-rating] -2) only returns updates one element). 我是Clojure的新手并尝试过研究更新和关联,并且似乎无法真正找到更新多个元素的方法( (assoc student-database [0 :sanity-rating] -2)只返回更新一个元素)。 To filter student-database to take out the student's who returned true I have 过滤学生数据库,以取出我所拥有的返回真实的学生

(defn unhinged?
 [record]
 (:enjoy-clojure? record))

(defn minus-two-students
 [student-database]
 (filter #(unhinged? %)
  (map student-database [0 1 2 3 4])))

And returns 并返回

({:enjoy-clojure? true, :name "johnny", :sanity-rating 2} {:enjoy-clojure? 
   true, :name "jilly", :sanity-rating 5} {:enjoy-clojure? true, :name 
   "janey", :sanity-rating 8})

Which works great but I also need it to update all their sanity-rating to -2. 哪个效果很好但我还需要它将所有的理智等级更新为-2。 Any helps/tips would be much appreciated. 任何帮助/提示将非常感激。

Here comes the reduce-kv version! 这是reduce-kv版本!

(defn adjust-sanity [student]
  (if (:enjoy-clojure? student)
    (assoc student :sanity-rating -2)
    student))

(reduce-kv (fn [m k v] (assoc m k (adjust-sanity v)))
           {}
           student-database)
=>
{0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9},
 1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2},
 2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2},
 3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2},
 4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}

Or another option with a helper function to update all a map's values: 或者使用辅助函数来更新所有地图值的另一个选项:

(defn update-vals [m f]
  (reduce-kv (fn [m' k v] (assoc m' k (f v))) {} m))
(update-vals student-database adjust-sanity)

the simplest would be like this: 最简单的是这样的:

(reduce-kv (fn [acc idx row]
             (assoc acc idx
                    (if (:enjoy-clojure? row)
                      (assoc row :sanity-rating -2)
                      row)))
           {}
           student-database)

;;=> {0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
;;    1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2}, 
;;    2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2}, 
;;    3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2}, 
;;    4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}

you can also do something like this: 你也可以这样做:

(reduce-kv (fn [res k {ec? :enjoy-clojure?}]
             (if ec?
               (assoc-in res [k :sanity-rating] -2)
               res))
           student-database
           student-database)

;;=> {0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
;;    1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2}, 
;;    2 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2}, 
;;    3 {:enjoy-clojure? true, :name "janey", :sanity-rating -2}, 
;;    4 {:enjoy-clojure? false, :name "jelly", :sanity-rating 10}}

You didn't say in your question that you want the function to returns only (= enjoy-clojure? true) records, but from your comments in the other answers, I feel that's what you really want. 你没有在你的问题中说你希望函数只返回(= enjoy-clojure? true)记录,但是根据你在其他答案中的评论,我觉得这就是你真正想要的。

So maybe this? 也许这个?

(defn unhinged?
  [record]
  (:enjoy-clojure? record))

(defn minus-two-students
  [student-database]
  (->> student-database
       vals
       (filter unhinged?)
       (map #(assoc % :sanity-rating -2))))

Output will be 输出将是

({:enjoy-clojure? true, :name "johnny", :sanity-rating -2} 
 {:enjoy-clojure? true, :name "jilly", :sanity-rating -2} 
 {:enjoy-clojure? true, :name "janey", :sanity-rating -2})

To update the entire db, you could do: 要更新整个数据库,您可以执行以下操作:

(def student-database
  {0 {:enjoy-clojure? false, :name "jimmy",:sanity-rating 9}
   1 { :enjoy-clojure? true, :name "johnny",:sanity-rating 2}
   2 { :enjoy-clojure? true, :name "jilly",:sanity-rating 5}
   3 { :enjoy-clojure? true, :name "janey",:sanity-rating 8}
   4 {:enjoy-clojure? false, :name "jelly",:sanity-rating 10}})

(defn update-db [db]
  (zipmap (keys db)
          (map (fn [student]
                 (cond-> student
                   (:enjoy-clojure? student)
                   (assoc :sanity-rating -2)))
               (vals db))))

(update-db student-database) ;;=> 
{0 {:enjoy-clojure? false, :name "jimmy", :sanity-rating 9}, 
 1 {:enjoy-clojure? true, :name "johnny", :sanity-rating -2} ...}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM