How to map a vector to a map and push duplicate key values into it?
This is my input data:
[[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]]
I want to map this to the following:
{:a [[1 2] [3 4] [5 6]] :b [[\a \b] [\c \d] [\e \f]]}
This is what I have done so far:
(defn- build-annotation-map [annotation & m] (let [gff (first annotation) remaining (rest annotation) seqname (first gff) current {seqname [(nth gff 3) (nth gff 4)]}] (if (not (seq remaining)) m (let [new-m (merge-maps current m)] (apply build-annotation-map remaining new-m))))) (defn- merge-maps [m & ms] (apply merge-with conj (when (first ms) (reduce conj ;this is to avoid [1 2 [3 4 ... etc. (map (fn [k] {k []}) (keys m)))) m ms))
The above results:
{:a [[1 2] [[3 4] [5 6]]] :b [[\a \b] [[\c \d] [\e \f]]]}
I seem to know that the problem is in merge maps, especially the function passed to merge with (conj), but after I hit it for a while, I'm ready to help me
I am generally a novice of lisp, especially clojure, so I also appreciate those comments that do not specifically address this issue, as well as my style, brain death structure and so on thank you!
Solution (in any case, close enough):
(group-by first [[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]]) => {:a [[:a 1 2] [:a 3 4] [:a 5 6]],:b [[:b \a \b] [:b \c \d] [:b \e \f]]}
Solution
(defn build-annotations [coll]
(defn build-annotations [coll] (reduce (fn [m [k & vs]] (assoc m k (conj (m k []) (vec vs)))) {} coll))
The most important question about your code is naming First of all, I don't know the meaning of comments, GFF and seqname, especially without knowing your code first The tide is also vague In clojure, the rest is usually called more depending on the context and whether a more specific name should be used
In your let statement, I may use deconstruction for the rest (rest annotation) of GFF (the first annotation), such as:
(let [[first & more] comment]...)
If you prefer to use (rest comment), I recommend using next, because if it is empty, it will return nil and allow you to write (if not remaining...) instead of (if not (SEQ remaining))...)
user> (next []) nil user> (rest []) ()
In clojure, unlike other lisps, empty lists are real
This article shows the standard of customary naming