假设我有一个嵌套的map结构,比如
{:val1 {:m1 1 :m2 2 :m3 2} :val2 {:m1 4 :m2 8 :m3 7}}这个示例只有两个值,但通常可以有更多的值。我知道每个嵌套映射的键都是相同的(上面示例中的:m1、:m2和:m3 )。我有一个关键字列表,比如说
[:m1 :m3]对于列表中给出的每个关键字,我想将每个内部映射的值除以某个数字,比如5。继续我的例子,我想要得到
{:val1 {:m1 1/5 :m2 2 :m3 2/5} :val2 {:m1 4/5 :m2 8 :m3 7/5}}我该怎么做呢?对于固定的内键,比如:m1,我可以这样做
(map #(update-in % [1 :m1] / 5) nested-map)但我不确定如何将其概括为一系列关键字。谢谢!
发布于 2017-08-30 19:15:55
跟随Clojure Cookbook的脚步,我会定义
(defn map-vals [f m]
(zipmap (keys m) (map f (vals m))))..。然后使用核心函数来做你想做的事情:
(defn map-inner-keys-with [ks f m]
(map-vals
(fn [vm] (into vm (map (juxt identity (comp f vm)) ks)))
m))例如,
(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}}发布于 2017-08-30 04:47:45
假设您的嵌套级别是恒定的(根据您的示例,这似乎是一个合理的假设),以下是一个有效的答案。注意,我提供的键是一个集合,如果你想使用一个向量,你可以简单地修改函数,将一个符号绑定到函数顶部的let中的hash-set调用。
(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})或者,如果您希望一次只传递一个密钥:
(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更改为函数来对此进行泛化。
(into {} (map (fn[[k v]] {k (reduce #(update %1 %2 / 2) v [:m1 :m3])}) example))发布于 2017-08-30 11:59:10
您可以首先定义一个在细节级别工作的函数:
(let [interesting-keys (set [:m1 :m3])]
(defn apply-effect [[k v]]
(if (interesting-keys k)
[k (/ v 5)]
[k v])))正如您所看到的,一些map条目值将被转换,而其他值将保持不变。
您的示例输入数据:
(def data {:val1 {:m1 1 :m2 2 :m3 2} :val2 {:m1 4 :m2 8 :m3 7}})因此,我们在这里查看外部结构,以便应用细节函数f
(defn make-changes [m f]
(->> m
(map (fn [[k v]]
[k (->> v
(map f)
(into {}))]))
(into {})))当然,f将是apply-effect
(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函数是否使用了此抽象两次:
(defn map-map-entries [f m]
(->> m
(map f)
(into {})))现在我们可以用map-map-entries回答这个问题了
(map-map-entries
(fn [[k v]]
[k (map-map-entries
apply-effect
v)])
data)https://stackoverflow.com/questions/45947561
复制相似问题