2011-08-13 75 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