2011-08-13 74 views
16

我還沒有找到很多文檔或編碼示例來對地圖的矢量進行操作。舉例來說,如果我有Clojure中的地圖處理矢量

(def student-grades 
[{:name "Billy" :test1 74 :test2 93 :test3 89} 
    {:name "Miguel" :test1 57 :test2 79 :test3 85} 
    {:name "Sandy" :test1 86 :test2 97 :test3 99} 
    {:name "Dhruv" :test1 84 :test2 89 :test3 94}]) 

,我想添加或測試平均一個新的鍵值對,它的功能應該在我閱讀了相關聯?另外,如果有人知道Clojure中的地圖矢量的任何參考/資源,請分享!非常感謝!

回答

10

在這種情況下,你想地圖一個函數在集合(這恰好是一個向量);對於集合中的每個元素(這恰好是一個地圖 - 不幸的命名碰撞),您想要生成一個新地圖,其中包含舊地圖的所有鍵值對,再加上一個新的鍵,比如:平均值

例如

(into [] ; optional -- places the answer into another vector 
    (map ; apply the given function to every element in the collection 
    (fn [sg] ; the function takes a student-grade 
     (assoc sg ; and with this student-grade, creates a new mapping 
     :avg ; with an added key called :avg 
     (/ (+ (:test1 sg) (:test2 sg) (:test3 sg)) 3.0))) 
    student-grades ; and the function is applied to your student-grades vector 
)) 

PS你可以使用(DOC FN-名),以得到它的文件;如果您是Clojure的新手,我建議與irc.freenode.net #clojure上的友好人員一起出去讀一本書 - 我最喜歡的書目是Programming Clojure,但我正在等待O'Reilly即將發佈的Clojure書,呼吸。

+0

非常感謝!我剛剛在clojuredocs.org周圍徘徊,似乎無法找到收藏集的相關示例。 – Adam

+1

沒問題!我認爲它不會成爲一個問題,一旦你習慣了它 - 功能性編程的美妙之處在於構建模塊只是堆積起來,因此在處理外部集合時,可以簡單地處理內部集合,抽象地作爲單純的元素,同樣,當編寫函數來轉換這些元素之一時,您不必擔心外部集合。你會得到它的竅門:) –

+2

你也可以使用'(mapv ...)'作爲方便'(到[](map ...))''中。 – Peeja

4

Hircus已經提供了一個很好的答案,但在這裏是比較另一種實現方式:

(defn average [nums] 
    (double (/ (apply + nums) (count nums)))) 

(map 
    #(assoc % :avg (average ((juxt :test1 :test2 :test3) %))) 
    student-grades) 

=> ({:avg 85.33333333333333, :name "Billy", :test1 74, :test2 93, :test3 89} etc....) 

評論請注意:

  • 它通常是值得分離出通用的功能,如「平均」成獨立的,功能強大的功能
  • juxt是一個非常有用的功能,用於從地圖中提取組件值的特定列表
+0

謝謝,我正在學習這麼多有用的功能,將添加juxt到該列表! – Adam

+0

不用擔心!附:在這種情況下使用juxt有點聰明,因爲它利用了可以使用關鍵字(「:test1」等)作爲函數的事實。但是,您可以將其與任意任意函數一起使用。 – mikera

+0

[發明者的悖論](https://en.wikipedia.org/wiki/Inventor%27s_paradox):有時解決一般問題比解決特定問題更容易。 – Zaz