从Clojure中的映射构建嵌套向量

从Clojure中的映射构建嵌套向量,clojure,functional-programming,hiccup,Clojure,Functional Programming,Hiccup,我有一组URL,一些URL有间接引用(作为向量)。任何没有间接引用的URL只有nil。我从以下测试图开始: {"URL 1" nil, "URL 2" ["indirect 1" "indirect 2"]} 我正在使用生成HTML报告,因此我需要以下输出: [:div "Imports: " [:ul [:li "URL 1"] [:li "URL 2"] [:ul [:li "indirect 1"] [:li "indirect 2"]

我有一组URL,一些URL有间接引用(作为向量)。任何没有间接引用的URL只有
nil
。我从以下测试图开始:

{"URL 1" nil,
 "URL 2" ["indirect 1" "indirect 2"]}
我正在使用生成HTML报告,因此我需要以下输出:

[:div "Imports: "
 [:ul
  [:li "URL 1"]
  [:li "URL 2"]
    [:ul
     [:li "indirect 1"]
     [:li "indirect 2"]
     [:li "indirect 3"]]]]
当URL没有间接引用时,返回nil会遇到一些问题。我当前的代码如下所示:

(defn list-imports
  [imports]
  (if-not (nil? imports)
    [:div "Imports: "
     [:ul
      (for [direct (keys imports)]
        [[:li direct]
         (if-let [indirects (get imports direct)]
           [:ul
             (for [indirect indirects]
               [:li indirect])]
           [:span])])]]
    [:div "Imports: none" [:br] [:br]]))
问题是,它正在退回这个

[:div
 "Imports: "
 [:ul
  ([[:li "URL 1"] [:span]]
   [[:li "URL 2"] [:ul ([:li "indirect 1"] [:li "indirect 2"])]])]]
我必须添加一个
[:span]
标记,作为间接导入为
nil
时的情况,我并不希望出现这种情况。。。但除此之外,它在那里输入
nil


另一个问题是它最终被封装在
()
和一个额外的向量中,因为我在for语句中做了很多事情。当我尝试用hiccup转换它时,我发现
[:li“URL 1”]不是有效的元素名。

这可能是构建hiccup标记的一个棘手方面。有时,将问题分解成更小的部分会有所帮助

(defn list-indirects
  [indirects]
  (when (seq indirects)
    [(into [:ul] (mapv (fn [i] [:li i]) indirects))]))

(defn list-imports
  [imports]
  (if (some? imports)
    [:div "Imports: "
     (into [:ul]
       (for [[url indirects] imports]
         (into [:li url] (list-indirects indirects))))]
    [:div "Imports: none" [:br] [:br]]))
这些函数应该为您提供所需的输出

(list-imports {"URL 1" nil
               "URL 2" ["indirect 1" "indirect 2"]})
=>
[:div "Imports: "
 [:ul
  [:li "URL 1"]
  [:li "URL 2"
   [:ul
    [:li "indirect 1"]
    [:li "indirect 2"]]]]]
此输出与您预期的输出略有不同,但我认为它更接近您实际需要的内容,即示例中的
[:li“URL 2”]
标记应包含
:ul
“indirects”的
:ul
作为有效的HTML


如果这些项目的顺序很重要,另一件需要注意的事情是,地图可能不会按您期望的方式排序,尤其是当您拥有一定数量的键时。当您遍历地图以构建hiccup时,
“URL 2”
可能位于
“URL 1”
之前。您可以通过使用元组向量或排序映射来解决此问题。

这非常好,非常感谢!我想我是想把太多的东西塞进一个函数。我甚至没有想过使用mapv,但现在它看起来很明显:)