首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure -更新嵌套地图中的每个内部地图

Clojure -更新嵌套地图中的每个内部地图
EN

Stack Overflow用户
提问于 2017-08-30 04:07:21
回答 4查看 910关注 0票数 1

假设我有一个嵌套的map结构,比如

代码语言:javascript
复制
{:val1 {:m1 1 :m2 2 :m3 2} :val2 {:m1 4 :m2 8 :m3 7}}

这个示例只有两个值,但通常可以有更多的值。我知道每个嵌套映射的键都是相同的(上面示例中的:m1、:m2和:m3 )。我有一个关键字列表,比如说

代码语言:javascript
复制
[:m1 :m3]

对于列表中给出的每个关键字,我想将每个内部映射的值除以某个数字,比如5。继续我的例子,我想要得到

代码语言:javascript
复制
{:val1 {:m1 1/5 :m2 2 :m3 2/5} :val2 {:m1 4/5 :m2 8 :m3 7/5}}

我该怎么做呢?对于固定的内键,比如:m1,我可以这样做

代码语言:javascript
复制
(map #(update-in % [1 :m1] / 5) nested-map)

但我不确定如何将其概括为一系列关键字。谢谢!

EN

回答 4

Stack Overflow用户

发布于 2017-08-30 19:15:55

跟随Clojure Cookbook的脚步,我会定义

代码语言:javascript
复制
(defn map-vals [f m]
  (zipmap (keys m) (map f (vals m))))

..。然后使用核心函数来做你想做的事情:

代码语言:javascript
复制
(defn map-inner-keys-with [ks f m]
  (map-vals
    (fn [vm] (into vm (map (juxt identity (comp f vm)) ks)))
    m))

例如,

代码语言:javascript
复制
(map-inner-keys-with [:m1 :m3] #(/ % 5)
                     {:val1 {:m1 1 :m2 2 :m3 2}
                      :val2 {:m1 4 :m2 8 :m3 7}})
=> {:val1 {:m1 1/5, :m2 2, :m3 2/5}, :val2 {:m1 4/5, :m2 8, :m3 7/5}}
票数 1
EN

Stack Overflow用户

发布于 2017-08-30 04:47:45

假设您的嵌套级别是恒定的(根据您的示例,这似乎是一个合理的假设),以下是一个有效的答案。注意,我提供的键是一个集合,如果你想使用一个向量,你可以简单地修改函数,将一个符号绑定到函数顶部的let中的hash-set调用。

代码语言:javascript
复制
(defn change-map [m f ks]
  (for [[k1 v1] m]
       (hash-map k1 (into {} (for [[k2 v2] v1]
                                  (if (contains? ks k2) [k2 (f v2)]
                                      [k2 v2]))))))

(change-map example #{:m1 :m3})

或者,如果您希望一次只传递一个密钥:

代码语言:javascript
复制
(defn change-map [m f & ks]
  (let [ks (apply hash-set ks)]
       (for [[k1 v1] m]
            (hash-map k1 (into {} (for [[k2 v2] v1]
                                       (if (contains? ks k2) [k2 (f v2)]
                                           [k2 v2])))))))

(change-map example #(/ % 2) :m1 :m3)

经过一番思考,上面的例子对我来说并不是很合适。并不是说他们错了,只是觉得太过工程化了。我认为下面的内容更接近你的想法,而且更简洁。显然,您可以通过将硬编码的/ 2更改为函数来对此进行泛化。

代码语言:javascript
复制
(into {} (map (fn[[k v]] {k (reduce #(update %1 %2 / 2) v [:m1 :m3])}) example))
票数 0
EN

Stack Overflow用户

发布于 2017-08-30 11:59:10

您可以首先定义一个在细节级别工作的函数:

代码语言:javascript
复制
(let [interesting-keys (set [:m1 :m3])]
  (defn apply-effect [[k v]]
    (if (interesting-keys k)
      [k (/ v 5)]
      [k v])))

正如您所看到的,一些map条目值将被转换,而其他值将保持不变。

您的示例输入数据:

代码语言:javascript
复制
(def data {:val1 {:m1 1 :m2 2 :m3 2} :val2 {:m1 4 :m2 8 :m3 7}})

因此,我们在这里查看外部结构,以便应用细节函数f

代码语言:javascript
复制
(defn make-changes [m f]
  (->> m
       (map (fn [[k v]]
              [k (->> v
                      (map f)
                      (into {}))]))
       (into {})))

当然,f将是apply-effect

代码语言:javascript
复制
(make-changes data apply-effect) 
;;=> {:val1 {:m1 1/5, :m2 2, :m3 2/5}, :val2 {:m1 4/5, :m2 8, :m3 7/5}}

仔细查看上面的make-changes函数是否使用了此抽象两次:

代码语言:javascript
复制
(defn map-map-entries [f m]
  (->> m
       (map f)
       (into {})))

现在我们可以用map-map-entries回答这个问题了

代码语言:javascript
复制
(map-map-entries
  (fn [[k v]]
    [k (map-map-entries
         apply-effect
         v)])
  data)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45947561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档