我正在研究一个问题,要求我计算一个班级中每个学生的平均成绩。
输入是一个lisp文件,格式如下:
( ((name studentname) (class hour grade) (class hour grade) ...)
((name studentname) (class hour grade) (class hour grade) ...) ...)
对于输出:我需要打印学生姓名和他们的GPA(该学生的成绩平均值),按平均成绩和班级平均值(每个独特班级的成绩平均值)排序。
到目前为止,这就是我所拥有的
(setq class '(((name Seymore) (eng 3 4.0) (mat 3 3.0) (his 3 4.0) (bio 3 2.0) (biol 1 4.0))
((name Ichahbod) (cs 3 3.0) (mat 3 4.0) (spe 2 4.0) (che 3 4.0) (chel 1 3.0) (lit 3 3.0))
((name Zackery) (mat 5 3.0) (eng 3 3.0) (jou 2 3.0) (phy 3 3.0) (phyl 1 4.0) (lit 2 4.0))
((name Tukerville) (soc 4 3.0) (mus 2 4.0) (jou 3 4.0) (geo 4 4.0) (geol 1 3.0) (eng 3 3.0))
((name Simonsays) (css 3 3.0) (ast 3 4.0) (spe 3 4.0) (cs 3 4.0) (spe 2 3.0) (dan 4 4.0))
((name Snicker) (eng 3 4.0) (phy 4 4.0) (css 3 2.0) (csl 1 4.0) (ped 2 3.0) (mat 3 3.0))
((name Glass) (mat 3 1.0) (eng 3 1.0) (ped 1 1.0) (bio 3 1.0) (biol 1 0.0) (che 3 1.0) (chel 1 1.0))))
;this function multiplies the hours * the grades
(defun product (hours grades)
(* hours grades)
)
;this function multiplies a set of grades
(defun sumofGrades (L)
(cond
((null L) 0) ;check if it is first
(t (+ (product (cdr (cdadar L)) (caddar L)))) ;first val then the second val
(sumofGrades (cdr L)) ;the rest of one
)
)
;to get the total , same as sum of grades but sum the second variables
(defun totalHours (L)
(cond
((null L) 0) ;check if it is first
(t (+ (product (caddar L) (caddar L)))) ;first val then the second val
(totalHours() (cdr L)) ;the rest of one
)
)
(defun gradepoint (L)
( / (sumofGrades L) (totalHours L))
)
我试图从辅助方法开始,因为我认为这将是最好的方法,它可能不是。当我运行sumofGrades时,我从第一个条目开始就像我需要的那样返回4.0,但它说它不是一个数字。我写这些方法是基于我需要对数字进行的基本数学运算,但此时我对下一步该怎么做感到困惑。
如果我需要倒带并采取不同的惯例我会失望,任何帮助都会受到赞赏。
答案 0 :(得分:3)
您的代码
(defun sumofGrades (L)
(cond
((null L) 0) ;check if it is first
(t (+ (product (cdr (cdadar L)) (caddar L)))) ;first val then the second val
(sumofGrades (cdr L)) ;the rest of one
)
)
让我们看一下:
(defun sumofGrades (L) ; please no camelCase in Lisp
(cond
((null L) 0) ;check if it is first <- what does this comment mean???
(t (+ (product (cdr (cdadar L)) (caddar L))))
; what is (+ (product (cdr (cdadar L)) (caddar L))) ?
; you are calling + with one argument. Why?
; what does a function like caddar mean?
; what is it supposed to do?
; no one reading your code will have an idea why
; caddar and not cdaadar, cdadaadr, or cdddddr...
; write better documented, or self-documenting code.
(sumofGrades (cdr L)) ;the rest of one <- what does this comment mean?
; what is (sumofGrades (cdr L)) ?
; is sumofGrades a variable checked in COND?
; should it be a function call?
; just as it is alone here, it does not make any sense.
; since T is always true, this clause is also never reached...
) ; <- please no dangling parentheses in Lisp
)
编译上述函数时,LispWorks说:
; (TOP-LEVEL-FORM 0)
;;;*** Warning in SUMOFGRADES: The following cond clause
;;; will never be processed: ((SUMOFGRADES (CDR L)))
摘要:sumofGrades
无法正常工作。 Lisp编译器已经抱怨它了。
关于风格的更多信息
全局变量:它们由DEFPARAMETER或DEFVAR定义。请勿使用SETQ
。
不要写
(setq class ...)
代替写:
(defparameter *class* ...
"the global variable *class* is a list of ...")
答案 1 :(得分:3)
首先定义一些通用平均函数:
(defun average (lst &key (key #'identity))
(when lst
(/ (reduce #'+ lst :key key) (length lst))))
定义一个成绩函数来检索给定班级中给定学生的成绩(不是必要的,但会更清楚):
(defun grade (class) (caddr class))
和成绩函数来检索学生的成绩:
(defun grades (student)
(cdr (find student class :key #'cadar)))
现在,您可以通过致电
找到学生的平均成绩(average (grades 'seymore ) :key #'grade)
=> 3.4
按照这个例子,你应该能够自己写出所有课程的平均值。
答案 2 :(得分:2)
您可能想尝试reduce
:
(mapcar (lambda (l)
(cons (second (first l))
(/ (reduce #'+ (rest l) :key #'third)
(1- (length l)))))
class)
==>
((SEYMORE . 3.4) (ICHAHBOD . 3.5) (ZACKERY . 3.3333333) (TUKERVILLE . 3.5)
(SIMONSAYS . 3.6666667) (SNICKER . 3.3333333) (GLASS . 0.85714287))
然后您可以使用sort
对此进行排序:
(sort * #'< :key #'cdr)
==>
((GLASS . 0.85714287) (ZACKERY . 3.3333333) (SNICKER . 3.3333333) (SEYMORE . 3.4)
(ICHAHBOD . 3.5) (TUKERVILLE . 3.5) (SIMONSAYS . 3.6666667))
此处*
是前一个表达式的值。
PS。由于这可能是h / w,我给出的是代码示例而不是完整的解决方案,我建议您使用我的代码然后询问另一个非常具体的问题,如果有什么不清楚的话。
PPS。一些风格的评论:
product
这样的功能,它只会让人感到困惑