2010-09-12 38 views
3

這是我的輸入數據:如何將矢量映射到地圖,重複鍵值?

[[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]] 

我想這映射到以下幾點:

{:a [[1 2] [3 4] [5 6]] :b [[\a \b] [\c \d] [\e \f]]} 

這是我到目前爲止有:

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

上述方法產生:

{:a [[1 2] [[3 4] [5 6]]] :b [[\a \b] [[\c \d] [\e \f]]]} 

在我看來很清楚,問題在於merge-maps,特別是與傳遞給merge-withconj)的函數有關,但是在將頭撞了一會兒之後,我即將準備好有人幫助我。

我是新來的lisp,特別是clojure,所以我也很感謝沒有具體解決這個問題的意見,還有我的風格,腦死亡構造等。謝謝!

(足夠接近,反正):

(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]]} 

回答

9
(defn build-annotations [coll] 
    (reduce (fn [m [k & vs]] 
      (assoc m k (conj (m k []) (vec vs)))) 
      {} coll)) 

關於你的代碼中,最顯著的問題是命名。首先,我不會,尤其是沒有第一次瞭解您的代碼,就不知道annotation,gffseqname是什麼意思。 current也很模糊。在Clojure中,remaining通常被稱爲more,具體取決於上下文,以及是否應使用更具體的名稱。

在您的let語句,gff (first annotation) remaining (rest annotation),我可能會趁解構的,是這樣的:

(let [[first & more] annotation] ...)

如果您願意使用(rest annotation)那麼我會用next而不是建議,因爲它會如果它是空的,則返回nil,並允許您寫入(if-not remaining ...)而不是(if-not (seq remaining) ...)

user> (next []) 
nil 
user> (rest []) 
() 

在Clojure中,與其他lisps不同,空列表是truthy。

This文章顯示了慣用命名的標準。

+0

感謝您的評論,它有很大的幫助。 – 2010-09-12 17:30:04

4
作品

至少在給定的數據集。

(defn build-annotations [coll] 
    (reduce 
    (fn [result vec] 
     (let [key (first vec) 
      val (subvec vec 1) 
      old-val (get result key []) 
      conjoined-val (conj old-val val)] 
     (assoc 
      result 
      key 
      conjoined-val))) 
    {} 
    coll)) 

(build-annotations [[:a 1 2] [:a 3 4] [:a 5 6] [:b \a \b] [:b \c \d] [:b \e \f]]) 

我很抱歉沒有對您的代碼進行改進。我只是在學習Clojure,它可以逐個解決問題而不是理解更大的代碼並找出問題。

4

雖然我已經在你的代碼沒有評論,我想這對我自己和與此解決方案提出了:

(defn build-annotations [coll] 
    (let [anmap (group-by first coll)] 
    (zipmap (keys anmap) (map #(vec (map (comp vec rest) %)) (vals anmap))))) 
2

這裏是我的入門槓桿組通過,雖然在這裏的幾個步驟是真正關心與返回的載體,而不是名單。如果你刪除一個要求,它變得簡單一點:

(defn f [s] 
    (let [g (group-by first s) 
     k (keys g) 
     v (vals g) 
     cleaned-v (for [group v] 
        (into [] (map (comp #(into [] %) rest) group)))] 
    (zipmap k cleaned-v))) 

取決於你真正想要的東西,你甚至可以用只做組由度日。

+0

'group-by'完全符合我的需要,實際上。謝謝! – 2010-09-12 17:31:20

2
(defn build-annotations [coll] 
    (apply merge-with concat 
     (map (fn [[k & vals]] {k [vals]}) 
       coll)) 

所以,

(map (fn [[k & vals]] {k [vals]}) 
    coll)) 

需要[鍵&值]的集合,並返回{鍵[值]}的列表

(apply merge-with concat ...list of maps...) 

需要的地圖列表,合併它們在一起,並且如果密鑰已經存在則連接值。

+0

謝謝,這實際上是我迄今爲止首選的解決方案。我喜歡它的簡潔,你的解釋非常清楚。 – 2010-09-14 01:33:18