Kingalione
Kingalione

Reputation: 4265

Clojure deciding between map and vector

I have two cases showing how the data that I'm working with can be formatted:

What I want is to identify the case and do case-based stuff with the data.

Here is what I have:

(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 ", "))))))

The output is not formatted right. I had to delete some code for the sscce. The output for case 2 should look like this:

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

The output for case 1 should look like this:

("val1" "val2" "val3")

The problem is that the function is currently working correctly (except for that formatting problem in this sscce) for case 2, but not for case 1. For case 1, it only prints the first letters of the keys out. I think it's because it jumps to the else block after checking the condition, but I don't know how to find a better condition which solves my problem.

Thanks for any help.

Upvotes: 0

Views: 112

Answers (2)

Dave Yarwood
Dave Yarwood

Reputation: 3010

A nice way to simplify this would be to use a multimethod. Depending on how the actual data is represented, your multimethod's dispatch function could be as simple as calling type on the input, with the possible dispatch values being something like clojure.lang.PersistentArrayMap and clojure.lang.PersistentVector. A safer dispatch method would allow for the possibility of using other types of sequential collections, such as lists and Java arrays, as well as other types of associative collections, such as a sorted map. You could do something like this:

(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"

These aren't exactly your expected outputs as you've given them in your question, as it is a little confusing to me what exactly your code is trying to accomplish, but hopefully this at least shows how dispatching different code for different types of arguments is easily done using multimethods.

Upvotes: 1

Kingalione
Kingalione

Reputation: 4265

Well I found it out on my own:

I used:

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

instead of the other condition. Now it works.

Upvotes: 0

Related Questions