【问题标题】:Clojure - transform nested mapClojure - 转换嵌套地图
【发布时间】:2016-11-14 18:39:35
【问题描述】:

我想从这样的嵌套地图创建mermaid 图表

{"a" {"b" {"c" nil
           "d" nil}}
 "e" {"c" nil
      "d" {"h" {"i" nil
                "j" nil}}}}

我认为它应该首先将嵌套地图转换为这种形式。那么它应该很容易。

[{:out-path "a" :out-name "a"
  :in-path  "a-b" :in-name "b"}
 {:out-path "a-b" :out-name "b"
  :in-path  "a-b-c" :in-name "c"}
 {:out-path "a-b" :out-name "b"
  :in-path  "a-b-d" :in-name "d"}
 {:out-path "e" :out-name "e"
  :in-path  "e-f" :in-name "f"}
 {:out-path "e" :out-name "e"
  :in-path  "e-c" :in-name "c"}
 {:out-path "e" :out-name "e"
  :in-path  "e-d" :in-name "d"}
 {:out-path "e-d" :out-name "d"
  :in-path  "e-d-h" :in-name "h"}
 {:out-path "e-d-h" :out-name "h"
  :in-path  "e-d-h-i" :in-name "i"}
 {:out-path "e-d-h" :out-name "h"
  :in-path  "e-d-h-j" :in-name "j"}]

编辑:

这是我创建的。但我完全不知道如何为结果图添加路径。

(defn myfunc [m]
  (loop [in m out []]
    (let [[[k v] & ts] (seq in)]
      (if (keyword? k)
        (cond
          (map? v)
          (recur (concat v ts)
                 (reduce (fn [o k2]
                           (conj o {:out-name (name k)
                                    :in-name  (name k2)}))
                         out (keys v)))
          (nil? v)
          (recur (concat v ts) out))
        out))))

【问题讨论】:

  • 您在尝试过的代码方面需要具体帮助吗?可以发一下吗?
  • @Bill,我需要帮助为每个项目添加“路径”。
  • 通常,您会将当前级别的路径声明(让)到一个变量中,然后将其添加到您正在构建的结构中,然后在您递归到下一个级别时将其传递给继续构建它。在这种情况下,多参数函数可能比循环更容易构建。
  • 应该将顶层地图的每个条目都放在单独的图表上,还是全部放在一张纸上? (如果后者是真的,它们之间会有交叉点,不像你的图片)

标签: clojure


【解决方案1】:

据我在美人鱼文档中所见,要绘制图形,以“x-->y”对的形式生成所有节点就足够了。

我们可以通过一些简单的递归函数来做到这一点(我相信图中没有太多级别可以担心堆栈溢出):

(defn map->mermaid [items-map]
  (if (seq items-map)
    (mapcat (fn [[k v]] (concat 
                          (map (partial str k "-->") (keys v))
                          (map->mermaid v)))
      items-map)))

在回复中:

user>
(map->mermaid {"a" {"b" {"c" nil
                         "d" nil}}
               "e" {"c" nil
                    "d" {"h" {"i" nil
                              "j" nil}}}})

;; ("a-->b" "b-->c" "b-->d" "e-->c" "e-->d" "d-->h" "h-->i" "h-->j")

所以现在你只需要像这样制作一个图表:

(defn create-graph [items-map]
  (str "graph LR"
       \newline
       (clojure.string/join \newline (map->mermaid items-map))
       \newline))

更新

您可以对实际的地图转换使用相同的策略,只需将当前路径传递给map->mermaid

(defn make-result-node [path name child-name]
  {:out-path path
   :out-name name
   :in-path (str path "-" child-name)
   :in-name child-name})

(defn map->mermaid
  ([items-map] (map->mermaid "" items-map))
  ([path items-map]
   (if (seq items-map)
     (mapcat (fn [[k v]]
               (let [new-path (if (seq path) (str path "-" k) k)]
                 (concat (map (partial make-result-node new-path k)
                              (keys v))
                         (map->mermaid new-path v))))
             items-map))))

在回复中:

user> 
(map->mermaid {"a" {"b" {"c" nil
                         "d" nil}}
               "e" {"c" nil
                    "d" {"h" {"i" nil
                              "j" nil}}}})

;; ({:out-path "a", :out-name "a", :in-path "a-b", :in-name "b"} 
;;  {:out-path "a-b", :out-name "b", :in-path "a-b-c", :in-name "c"} 
;;  {:out-path "a-b", :out-name "b", :in-path "a-b-d", :in-name "d"} 
;;  {:out-path "e", :out-name "e", :in-path "e-c", :in-name "c"} 
;;  {:out-path "e", :out-name "e", :in-path "e-d", :in-name "d"} 
;;  {:out-path "e-d", :out-name "d", :in-path "e-d-h", :in-name "h"} 
;;  {:out-path "e-d-h", :out-name "h", :in-path "e-d-h-i", :in-name "i"} 
;;  {:out-path "e-d-h", :out-name "h", :in-path "e-d-h-j", :in-name "j"})

【讨论】:

  • 我写了和你类似的东西。问题是密钥重复时。您的结果图如下所示i.imgur.com/padT6h7.png
  • so.. 那么最好有一个“美人鱼”代码的例子,生成你想要的图表,我不太熟悉它..
  • 或者你的那张照片意味着两张不同的图表?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 2012-07-19
  • 1970-01-01
  • 2015-01-28
相关资源
最近更新 更多