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

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>