【问题标题】:How to use assoc-in to update multiple values in a map? (Clojure)如何使用 assoc-in 更新地图中的多个值? (Clojure)
【发布时间】:2018-02-26 19:27:14
【问题描述】:

我正在尝试更新具有“enjoy-clojure”的每一行?将真正的“健全性评级”返回为 -2(即 johnny 的健全性评级将更新为 -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}}) 

我是 Clojure 的新手,曾尝试研究 update 和 assoc,但似乎真的找不到更新多个元素的方法((assoc student-database [0 :sanity-rating] -2) 只返回更新一个元素)。过滤学生数据库以取出返回真实的学生我有

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

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

然后返回

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

效果很好,但我还需要它来将他们的所有理智评级更新为 -2。任何帮助/提示将不胜感激。

【问题讨论】:

    标签: clojure clojurescript


    【解决方案1】:

    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}}
    

    或者另一个带有辅助函数的选项来更新所有地图的值:

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

    【讨论】:

    • 太好了!但是,这会打印出所有人,有没有办法我可以打印出“enjoy-clojure?true”学生而忽略虚假学生?
    • @Student1860 (->> (update-vals student-database adjust-sanity) (vals) (filter :enjoy-clojure?))
    【解决方案2】:

    您没有在问题中说您希望该函数仅返回 (= enjoy-clojure? true) 记录,但是从其他答案中的 cmets 来看,我觉得这就是您真正想要的。

    所以也许是这个?

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

    输出将是

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

    【讨论】:

      【解决方案3】:

      要更新整个数据库,您可以这样做:

      (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} ...}
      

      【讨论】:

      • 太好了!但这会打印出所有人,我可以只打印出“enjoy-clojure?true”学生吗?
      • 当然,只需将(map ...) 参数改为zipmap 并将map 更改为filter
      • 谢谢!我对 zipmaps 还不太熟悉,所以我很抱歉,但我究竟如何将 (map ...) 参数带到 zipmap ?我在做类似(zipmap (keys db [0 1 2 3 4]) 的事情吗?我知道这行不通,但仍在努力学习这种语言
      • 我的意思是这样的:(filter (fn [student] (cond-> student (:enjoy-clojure?student) (assoc :sanity-rating -2))) (vals student-database) )
      【解决方案4】:

      最简单的应该是这样的:

      (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}}
      

      你也可以这样做:

      (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}}
      

      【讨论】:

      • 嗯,我实际上将它们设置为“-2”的值,而不是减少它们。不过谢谢!
      猜你喜欢
      • 2022-12-18
      • 2019-05-01
      • 1970-01-01
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多