1

我是一名大学讲师,试图在获得一点 Clojure 乐趣的同时计算我的成绩。我已经将我所有的学生编号及其相应的成绩列成如下所示的列表:

(def grades-1 (let [s18129  [100    70  85  71  85]  
                    s18121  [80 75  85  81  85]
                    r18131  [75 60  80  56  75] ...])
                    ;; r before the number is shorthand for repeater 
                    ;; and not important to this question

我希望调整成绩,使这些向量中的一、二、三、四、五年级的权重分别为 10%、20%、15%、25% 和 30%。为了帮助我完成这项任务,我创建了一个辅助函数:

(defn percentify
  "adjust raw score to weighted percentile"
  [raw percentile]
  (* (/ raw 100) percentile))

我想创建另一个函数,该函数将映射成绩列表,并根据其位置,以向量中每个元素的特定权重将百分比函数应用于每个学生的成绩。这就是我现在正在使用的东西,但我无法让它在 repl 中工作。我认为这与我构建班级数据的方式有关,或者我对 println 的使用感到困惑。

(defn finalize [grades-list]
(let [[[student] [a b c d e]] grades-list]
  (println
   (percentify a 10.0)
   (percentify b 20.0)
   (percentify c 15.0)
   (percentify d 25.0)
   (percentify e 30.0))))

然后我想调用这个函数来以可读的形式返回带有学生人数的最终成绩。有人可以帮助我走上正轨吗?

4

3 回答 3

3

首先,您似乎将每个学生的成绩向量分配给let表单中的单独本地。要跨所有等级向量映射函数,您需要首先将它们放入单个数据结构中:

(def grades-1 [[100    70  85  71  85]  
               [80 75  85  81  85]
               [75 60  80  56  75]])

现在,将权重向量应用于等级向量的函数将很有用(percentify这是您的原始函数):

;; taking weights first for convenient use with partial
(defn percentify-vector [pvec rvec]
  (mapv percentify rvec pvec))

最后,我们可以将上述内容映射到等级向量的集合中:

(mapv (partial percentify-vector [10.0 20.0 15.0 25.0 30.0]) grades-1)
于 2014-02-14T10:15:59.517 回答
1

数据自然是从学生编号(字符串)到成绩向量的映射:

(def grades-1 {"s18129"  [100 70  85  71  85]  
               "s18121"  [80 75  85  81  85]
               "r18131"  [75 60  80  56  75]})

...以及要应用于上述内容的权重向量:

(def grade-weights [10 20 15 25 30])

...制作一张从学生编号到最终成绩的地图。我们如何考虑这一点?

根据给weights定向量计算平均值的函数是

(fn [grades] (/ (reduce + 0.0 (map * weights grades)) (reduce + weights)))

... 在哪里

  • 的初始值0.0强制使用浮点运算和
  • 权重不需要加起来为 1.0 或 100 或任何数字。包括缩放。

以下将 的每个值转换为该值a-map的函数f

(fn [f a-map] (into {} (map (fn [[k v]] [k (f v)]) a-map)))

因此,从成绩向量图和权重向量提供最终成绩图的函数是......

(defn av-grades [gt weights]
  (let [weight-av (fn [grades]
                    (/ (reduce + 0.0 (map * weights grades)) (reduce + weights)))
        convert-map (fn [f a-map] 
                      (into {} (map (fn [[k v]] [k (f v)]) a-map)))]
    (convert-map weight-av gt)))

而且,果然,...

=>(av-grades grades-1 grade-weights)
{"r18131" 68.0, "s18121" 81.5, "s18129" 80.0}
于 2014-02-25T11:47:43.420 回答
0

我无法改进 Michał Marczyk 的回答,但我会建议一个可能的替代方案。目前,这可能对您的需求有点过分了。您想要做的基本上是矩阵乘法:您将矩阵乘以向量以产生向量。如果需要,这可以直接使用 core.matrix 库来完成。假设单个项目等级用于测验。首先,您需要在加载 core.matrix 库的情况下运行 Clojure,例如使用 Leiningen。然后在 REPL 或文件中,你可以这样做:

(use 'clojure.core.matrix)

;; Define quiz grade matrix: Each row is a student, each column is a quiz.
(def quiz-grades [[100 70  85  71  85]
                  [ 80 75  85  81  85]
                  [ 75 60  80  56  75]])

;; Define weights representing contributions of each quiz to the final grade.
(def quiz-weights [0.10 0.20 0.15 0.25 0.30])

在这里,我将测验的权重定义为表示 1 的小数的小数,而不是整数,但是使用 , 或类似的 core.matrix 函数可以很容易地在两种表示之间map进行mapv转换emap。现在您可以像这样获得每个学生的最终成绩:

user=> (mmul quiz-grades quiz-weights)
[80.0 81.5 68.0]

(注意:core.matrix 有不同的向量和矩阵的底层实现。在我的示例中,我使用了默认的持久向量实现,其中向量和矩阵等效于常规 Clojure 向量和向量的向量。为了在很容易实现不同的实现,最好将上面的 Clojure 向量嵌入到对函数的调用中matrix,但这对于持久向量实现来说不是必需的。)

于 2014-02-14T17:49:30.840 回答