决定地图和矢量之间的Clojure

时间:2014-09-15 10:16:35

标签: clojure

我有两个案例展示了我正在使用的数据如何格式化:

  • 案例1:

    {:key ["val1" "val2" "val3"]}
    
  • 案例2:

    {:key {"Title1" ["Val1" "Val2"] "Title2" ["Val3" "Val4"] "Title3" []}}
    

我想要的是识别案例并用数据做基于案例的事情。

这就是我所拥有的:

(let [val {"Produkt" ["bla" "blub"] "Test" ["12" "34" "45"]}]
  (cond
    (not (= (some map? val) nil))
      (for [v val]
        (str v ", "))
    :else
      (for [v val]
        (do (first v)
          (for [c (second v)] 
            (str c ", "))))))

输出格式不正确。我不得不删除sscce的一些代码。案例2的输出应如下所示:

("Produkt" ("12, " "34, " "45, ") "Test" ("bla, " "blub, "))

案例1的输出应如下所示:

("val1" "val2" "val3")

问题在于,对于案例2,该函数当前正在正常工作(除了此sscce中的格式化问题),但不适用于案例1.对于案例1,它仅打印出键的第一个字母。我认为这是因为它在检查条件后会跳转到else块,但我不知道如何找到一个更好的条件来解决我的问题。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

简化此操作的一种好方法是使用multimethod。根据实际数据的表示方式,您的多方法调度功能可以像在输入上调用type一样简单,可能的调度值类似于clojure.lang.PersistentArrayMapclojure.lang.PersistentVector。更安全的调度方法将允许使用其他类型的顺序集合(例如列表和Java数组)以及其他类型的关联集合(例如有序映射)。你可以这样做:

(defmulti foo (juxt map? sequential?))

(defmethod foo [true false]  ; input is a map of some sort
  [val]
  (mapcat (fn [[k vs]] [k (apply str (interpose ", " vs))]) val))

(defmethod foo [false true] ; input is a list, vector, etc.
  [val]
  (apply str (interpose ", " val)))

(foo {"Produkt" ["bla" "blub"] "Test" ["12" "34" "45"]})
;=> ("Produkt" "bla, blub" "Test" "12, 34, 45")

(foo ["val1" "val2" "val3"])    
;=> "val1, val2, val3"

这些并不完全是您在问题中给出的预期输出,因为对我来说有点令人困惑的是您的代码正在尝试完成什么,但希望这至少说明了如何为不同的代码调度不同的代码使用multimethods可以轻松完成参数类型。

答案 1 :(得分:0)

我自己发现了它:

我用过:

(if-not (some vector? val) 
  ...
)

而不是其他条件。现在它有效。