如何在 Clojure 中更新 Ingoring 第一级
how to update-in ingoring the first level in clojure
使用更新输入时,我们需要提供元素的完整路径。但是,如果我想更新二级键为 :MaxInclude
的所有元素怎么办?
例如输入是
(def a {:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude "100.02"},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude "100"}
})
所需的输出是(根据类型将 MaxInclude 从字符串转换为 float/int):
{:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude 100.02},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude 100}
}
(into {}
(map (fn [[k v]]
{k (if (contains? v :MaxInclude)
(update-in v [:MaxInclude] read-string)
v)})
a))
在这里,我映射键值对并将每个键值对解构为 k 和 v。然后,如果值包含 :MaxInclude
,我将对值使用 update-in
。最后,我将列表中的对 into
哈希映射。
备注:
- 如果任何主地图的值不是索引集合,这将在
contains?
上出错。
- 我使用
read-string
作为将字符串转换为数字的便捷方式,就像 Clojure reader 在编译作为数字文字的字符串时所做的一样。这种方法可能有缺点。
我在想,如果有一个像 update-in
这样的函数可以匹配键谓词函数而不是精确的键值,那就太好了。这是我想出的:
(defn update-all
"Like update-in except the second parameter is a vector of predicate
functions taking keys as arguments. Updates all values contained at a
matching path. Looks for keys in maps only."
[m [key-pred & key-preds] update-fn]
(if (map? m)
(let [matching-keys (filter key-pred (keys m))
f (fn [acc k]
(update-in acc [k] (if key-preds
#(update-all %
key-preds
update-fn)
update-fn)))]
(reduce f m matching-keys))
m))
有了这个,您需要做的就是:
(update-all a [= #{:MaxInclude}] read-string)
=
用作第一个键匹配函数,因为它在传递一个参数时总是 returns true。第二个是利用集合是函数这一事实。此函数使用非优化递归,但调用堆栈的深度只会与匹配映射级别的数量一样深。
使用更新输入时,我们需要提供元素的完整路径。但是,如果我想更新二级键为 :MaxInclude
的所有元素怎么办?例如输入是
(def a {:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude "100.02"},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude "100"}
})
所需的输出是(根据类型将 MaxInclude 从字符串转换为 float/int):
{:store {:type "varchar"},
:amount {:nullable true, :length nil, :type "float", :MaxInclude 100.02},
:unit {:type "int"},
:unit-uniform {:type "int" :MaxInclude 100}
}
(into {}
(map (fn [[k v]]
{k (if (contains? v :MaxInclude)
(update-in v [:MaxInclude] read-string)
v)})
a))
在这里,我映射键值对并将每个键值对解构为 k 和 v。然后,如果值包含 :MaxInclude
,我将对值使用 update-in
。最后,我将列表中的对 into
哈希映射。
备注:
- 如果任何主地图的值不是索引集合,这将在
contains?
上出错。 - 我使用
read-string
作为将字符串转换为数字的便捷方式,就像 Clojure reader 在编译作为数字文字的字符串时所做的一样。这种方法可能有缺点。
我在想,如果有一个像 update-in
这样的函数可以匹配键谓词函数而不是精确的键值,那就太好了。这是我想出的:
(defn update-all
"Like update-in except the second parameter is a vector of predicate
functions taking keys as arguments. Updates all values contained at a
matching path. Looks for keys in maps only."
[m [key-pred & key-preds] update-fn]
(if (map? m)
(let [matching-keys (filter key-pred (keys m))
f (fn [acc k]
(update-in acc [k] (if key-preds
#(update-all %
key-preds
update-fn)
update-fn)))]
(reduce f m matching-keys))
m))
有了这个,您需要做的就是:
(update-all a [= #{:MaxInclude}] read-string)
=
用作第一个键匹配函数,因为它在传递一个参数时总是 returns true。第二个是利用集合是函数这一事实。此函数使用非优化递归,但调用堆栈的深度只会与匹配映射级别的数量一样深。