Data structures clojure中向量的分解列表中每个元素的映射

Data structures clojure中向量的分解列表中每个元素的映射,data-structures,vector,clojure,mapping,destructuring,Data Structures,Vector,Clojure,Mapping,Destructuring,我是一名大学教师,我想找点乐子,同时计算我的成绩。我已将我所有的学生编号及其相应的成绩列成如下所示: (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

我是一名大学教师,我想找点乐子,同时计算我的成绩。我已将我所有的学生编号及其相应的成绩列成如下所示:

(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
user=> (mmul quiz-grades quiz-weights)
[80.0 81.5 68.0]
我希望对这些年级进行调整,使这些向量中的第一、二、三、四和五年级的权重分别为10%、20%、15%、25%和30%。为了帮助我完成此任务,我创建了一个助手函数:

(defn percentify
  "adjust raw score to weighted percentile"
  [raw percentile]
  (* (/ raw 100) percentile))
;; taking weights first for convenient use with partial
(defn percentify-vector [pvec rvec]
  (mapv percentify rvec pvec))
我想创建另一个函数,它将映射到成绩列表,并根据向量中每个元素的位置,以特定权重将percentify函数应用于每个学生的成绩。这就是我现在正在使用的,但我无法使它在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))))

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

首先,您似乎在以
let
的形式将每个学生的分数向量分配给一个单独的局部变量。要跨所有等级向量映射函数,首先需要将它们放在单个数据结构中:

(def grades-1 [[100    70  85  71  85]  
               [80 75  85  81  85]
               [75 60  80  56  75]])
现在,将权重向量应用于等级向量的函数将非常有用(
percentify
这是您的原始函数):

最后,我们可以在坡度向量集合中映射上述内容:

(mapv (partial percentify-vector [10.0 20.0 15.0 25.0 30.0]) grades-1)

首先,您似乎在以
let
的形式将每个学生的分数向量分配给一个单独的局部变量。要跨所有等级向量映射函数,首先需要将它们放在单个数据结构中:

(def grades-1 [[100    70  85  71  85]  
               [80 75  85  81  85]
               [75 60  80  56  75]])
现在,将权重向量应用于等级向量的函数将非常有用(
percentify
这是您的原始函数):

最后,我们可以在坡度向量集合中映射上述内容:

(mapv (partial percentify-vector [10.0 20.0 15.0 25.0 30.0]) grades-1)

我无法改进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的分数,而不是整数,但使用
map
mapv
,或类似的core.matrix函数
emap
,很容易在这两种表示之间进行转换。现在,您可以按如下方式获得每个学生的最终分数:

(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
user=> (mmul quiz-grades quiz-weights)
[80.0 81.5 68.0]

(注意:core.matrix有不同的向量和矩阵的底层实现。在我这里的示例中,我使用了默认的持久向量实现,其中向量和矩阵等效于常规Clojure向量和向量的向量。为了在不同的实现之间轻松切换,最好嵌入在调用函数
matrix
时关闭上述向量,但持久化向量实现不需要这样做。)

我无法改进MichałMarczyk的答案,但我会提出一个可能的替代方案。目前,这可能过于满足您的需要。您需要做的基本上是矩阵乘法:将矩阵乘以向量以生成向量。如果需要,可以直接使用core.matrix库。Le假设单项成绩用于测验。首先,您需要在加载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的分数,而不是整数,但使用
map
mapv
,或类似的core.matrix函数
emap
,可以很容易地在这两种表示之间进行转换。现在,您可以像这样获得每个学生的最终分数:

(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
user=> (mmul quiz-grades quiz-weights)
[80.0 81.5 68.0]

(注意:core.matrix有不同的向量和矩阵的底层实现。在我这里的示例中,我使用了默认的持久向量实现,其中向量和矩阵等效于常规Clojure向量和向量的向量。为了在不同的实现之间轻松切换,最好嵌入Clojure vectors在调用函数
matrix
,但这不是永久性vector实现所必需的。)

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

(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])
…绘制一张从学生人数到最终成绩的地图。我们如何考虑这一点

根据给定的
权重
向量计算平均值的函数为

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

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

(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])
…绘制一张从学生人数到最终成绩的地图。我们如何考虑这一点

根据给定的
权重
向量计算平均值的函数为

(fn [grades] (/ (reduce + 0.0 (map * weights grades)) (reduce + weights)))
…在哪里

  • 0.0
    的初始值强制使用float