在Lisp

时间:2016-11-29 22:30:39

标签: lisp common-lisp average

我正在研究一个问题,要求我计算一个班级中每个学生的平均成绩。

输入是一个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,但它说它不是一个数字。我写这些方法是基于我需要对数字进行的基本数学运算,但此时我对下一步该怎么做感到困惑。

如果我需要倒带并采取不同的惯例我会失望,任何帮助都会受到赞赏。

3 个答案:

答案 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。一些风格的评论:

  1. 不要定义像product这样的功能,它只会让人感到困惑
  2. 不要使用CamelCase,而是使用normal-lisp-dashes
  3. 不要使用挂衣
  4. 使用Emacs缩进代码,现在无法读取。