0

我正在寻找一个函数来实现以下示例结果:

{"foo1"      "baz"
 "foo2.bar"  "baz"
 "foo2.bar2" "baz"
 "foo3_bar"  "baz"}
=>
{:foo1 "baz"
 :foo2 {:bar  "baz"
        :bar2 "baz"}
 :foo3 {:bar  "baz"}}

正如人们所看到的,它与经典有点不同,因为必须首先以点和下划线后缀转换为哈希映射(而不是通常的)的方式deep-merge对键进行化。keyword#[_\.]=> -

4

3 回答 3

2
(defn parse-keys-and-merge
  [hm]
  (reduce-kv (fn [hm k v]
               (assoc-in hm (map keyword (clojure.string/split k #"[\._]"))
                         (if (map? v)
                           (parse-keys-and-merge v)
                           v)))
             {} hm))

这不适用于您的哈希映射,因为您的哈希映射没有说明条目:foo应该是"baz"还是{:bar "baz", :bar2 "baz"}。使用固定的哈希映射它可以工作:

(parse-keys-and-merge {"foo2_bar" "baz", "foo.bar2" "baz", "foo.bar" "baz"})
;; {:foo {:bar "baz", :bar2 "baz"}, :foo2 {:bar "baz"}}
于 2013-10-27T13:59:12.280 回答
0

在@lgrapenthin 的启发下,我想出了这个解决方案。它的优点是短而简洁,缺点是昂贵(这对我的用例来说还不错),覆盖策略由 Clojure 的哈希映射排序决定(也就是用户的未确定):

(defn- deep-merge [& maps]
  (if (every? map? maps)
    (apply merge-with deep-merge maps)
    (last maps)))

(defn- str-keys-to-map [[k v]]
  (let [ks (map keyword (filter not-empty (string/split k #"[\._]")))]
    (when-not (empty? ks) (assoc-in {} ks v))))

(defn deep-keywordize-keys [m]
  (->> m (map str-keys-to-map) (apply deep-merge)))
于 2013-11-01T12:53:03.067 回答
-1

您可以使用这样的功能。请注意,可以对其进行优化以进行尾递归。

        (defn deep-hashmap-merge
          [ m ]
          (let
            [
            tget (fn [r k d]
                    (let
                      [ t (get r k d)]
                      (if (associative? t) t d))) 
            get-keylist-value (fn [r [k & ks] kv]
                              (if (nil? ks)
                                (assoc r k kv)
                                (assoc r k (get-keylist-value (tget r k {}) ks kv))))     
            ]
              (reduce #(get-keylist-value %1 (map keyword (clojure.string/split (first %2) #"[_\.]")) ( second %2)) {} m)
            )
          )

然后输出将是:

              user=> (deep-hashmap-merge 
              #_=> {"foo"      "baz"
              #_=>  "foo.bar"  "baz"
              #_=>  "foo.bar2" "baz"
              #_=>  "foo2_bar" "baz"})

              {:foo {:bar "baz", :bar2 "baz"}, :foo2 {:bar "baz"}}
于 2013-10-27T13:40:39.153 回答