clojure - 从父/子关系创建嵌套映射

标签 clojure

给定一组父/子关系,我如何构建一个嵌套 map 来显示此结构?

例如,我如何转换此数据:

({"child"  "1.1",
  "parent" "1"}
 {"child"  "1.2",
  "parent" "1"}
 {"child"  "1.3",
  "parent" "1"}
 {"child"  "1.4",
  "parent" "1"}
 {"child"  "1.1.1",
  "parent" "1.1"}
 {"child"  "1.1.2",
  "parent" "1.1"}
 {"child"  "2.1",
  "parent" "2"}
 {"child"  "2.2",
  "parent" "2"}
 {"child"  "2.3",
  "parent" "2"})

进入此:

{"1" {"1.1" {"1.1.1" {}
             "1.1.2" {}}
      "1.2" {}
      "1.3" {}
      "1.4" {}}
 "2" {"2.1" {}
      "2.2" {}
      "2.3" {}}}

我正在使用的实际数据是:

({"child" "94bf72cb-01cd-4430-b669-b2e954b5639b",
  "parent" "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef"}
 {"child" "8c9c57a0-d20d-4474-9afb-c9d17df83a91",
  "parent" "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef"}
 {"child" "73d2a203-e3c1-4d2f-aaf8-a9f2e870792b",
  "parent" "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef"}
 {"child" "669fe949-057f-43c0-af7b-ff39594a183d",
  "parent" "6378daf6-3b7f-4cf4-8156-a50cf5f7b6ef"}
 {"child" "1ceff8fe-a0a8-46ad-81a8-d13fb837aaf6",
  "parent" "94bf72cb-01cd-4430-b669-b2e954b5639b"}
 {"child" "ba96a425-a3f0-4ce5-8c19-6ea9add14013",
  "parent" "94bf72cb-01cd-4430-b669-b2e954b5639b"}
 {"child" "160f34ac-68b9-4c8e-930b-1ab6df895df4",
  "parent" "1ce9b863-5681-4660-85e7-fbd0cc184aed"}
 {"child" "58825b50-23bc-4204-8f8d-c9a9d3ac8beb",
  "parent" "1ce9b863-5681-4660-85e7-fbd0cc184aed"}
 {"child" "4b1763f9-8380-4507-9a8f-5c86878e49a9",
  "parent" "1ce9b863-5681-4660-85e7-fbd0cc184aed"})

最佳答案

您可以将子父关系转换为邻接列表,然后遍历非循环有向图以创建嵌套映射。

(defn adjacency-list [coll]
  (reduce (fn [r {p "parent" c "child"}]
            (-> r
              (update-in [:counts p] #(or % 0))
              (update-in [:counts c] #(if % (inc %) 1))
              (update-in [:adjacency p] #(if % (conj % c) [c]))))
          {}
          coll))

(defn root-nodes [counts]
  (mapv key
        (filter (comp zero? val) counts)))

(defn traverse [m al roots]
  (reduce (fn [r k]
            (assoc r k
                   (if-let [v (get al k)]
                     (traverse {} al v)
                     {})))
          m
          roots))

(def data '({"child" "1.1", "parent" "1"} {"child" "1.2", "parent" "1"} {"child" "1.3", "parent" "1"} {"child" "1.4", "parent" "1"} {"child" "1.1.1", "parent" "1.1"} {"child" "1.1.2", "parent" "1.1"} {"child" "2.1", "parent" "2"} {"child" "2.2", "parent" "2"} {"child" "2.3", "parent" "2"}))

(let [{:keys [counts adjacency]} (adjacency-list data)]
  (clojure.pprint/pprint (traverse {} adjacency (root-nodes counts))))

;=> {"2" {"2.3" {}, "2.2" {}, "2.1" {}},
;    "1" {"1.4" {}, "1.3" {}, "1.2" {}, "1.1" {"1.1.2" {}, "1.1.1" {}}}}

关于clojure - 从父/子关系创建嵌套映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27771187/

相关文章:

clojure - 为什么我不能在 js->clj 生成的序列中调用 seq 函数?

java - 在没有注释的情况下模拟Java中的静态方法

clojure - 将数据库访问/功能放在 clojure 应用程序中的何处?

loops - Clojure:当当前变量的值与我的输入值匹配时,我如何让 for 循环停止?

clojure - 如何实现原始程序 "apply"

regex - 我如何在 clojure 的正则表达式中获得最后一组

emacs - 如何为特定模式设置 Emacs 填充列?

clojure - 我如何使用 Clojure 及其 Web 框架实现类似于 Rails 的 url_for 的功能?

javascript - 从谷歌编译器中排除函数

clojure - 在 Clojure 中导入 Java 类