在hashmap中更新多个值的最佳方法是什么?

时间:2013-12-19 10:09:38

标签: clojure

我有这样的哈希映射:

{:key1 "aaa bbb ccc" :key2 "ddd eee" :key3 "fff ggg" :do-not-split "abcdefg hijk"}

我想分割一些字符串来获取向量:

; expected result
{:key1 ["aaa" "bbb" "ccc"] :key2 ["ddd" "eee"] :key3 ["fff" "ggg"] :do-not-split "abcdefg hijk"}

我现在使用update-in三次,如下所示,但看起来很难看。

(-> my-hash (update-in [:key1] #(split % #"\s")) 
            (update-in [:key2] #(split % #"\s")) 
            (update-in [:key3] #(split % #"\s")))

我希望有点像(update-all my-hash [:key1 :key2 :key3] fn)

3 个答案:

答案 0 :(得分:4)

您可以使用reduce

user=> (def my-hash {:key1 "aaa bbb ccc" :key2 "ddd eee" :key3 "fff ggg"})
#'user/my-hash
user=> (defn split-it [s] (clojure.string/split s #"\s"))
#'user/split-it
user=> (reduce #(update-in %1 [%2] split-it) my-hash [:key1 :key2 :key3])
{:key3 ["fff" "ggg"], :key2 ["ddd" "eee"], :key1 ["aaa" "bbb" "ccc"]}

答案 1 :(得分:2)

只需根据决定是否分割的函数映射值。

user=> (def x {:key1 "aaa bbb ccc" 
               :key2 "ddd eee" 
               :key3 "fff ggg" 
               :do-not-split "abcdefg hijk"})
#'user/x

user=> (defn split-some [predicate [key value]] 
         (if (predicate key) 
           [key (str/split value #" ")] 
           [key value]))
#'user/split-some

user=> (into {} (map #(split-some #{:key1 :key2 :key3} %) x))
{:do-not-split "abcdefg hijk", :key3 ["fff" "ggg"], :key2 ["ddd" "eee"], :key1 ["aaa" "bbb" "ccc"]}

答案 2 :(得分:0)

这是解决问题的另一种方式。

想一想:如果你的字符串在列表中,你会如何处理它?<​​/ p>

答案是您可以使用map来获取向量列表:

(map #(split % #"\s") list-of-strings)

如果你认为更难以得出结论,你真正想要的是映射一个函数而不是地图的。显然map在这里不起作用,因为它仅适用于序列。

但是,是否有通用版本的地图?事实证明有!它被称为fmap,来自仿函数的概念,您现在可以忽略它。这就是你如何使用它:

(fmap my-hash #(split % #"\s"))

现在看看意图如何更清晰了?

唯一的缺点是fmap不是核心功能,但它可以通过algo.generic库获得。

当然,如果在这个阶段包含一个新库感觉太多,你总是可以在this link中从库本身中获取源代码 - 并赋予其作者属性:

(into (empty my-hash) (for [[k v] my-hash] [k (your-function-here v)]))