返回Sum的Lisp函数

时间:2015-02-10 08:43:53

标签: list sum lisp iteration clisp

我正在尝试编写一个奇怪的函数,所以请耐心等待。此函数应将列表L作为参数并具有sum变量。如果L不是列表,则应返回nil。否则,它应遍历列表中的每个元素并执行以下操作:

  • 如果元素是一个数字且小于零,则应从总和中减去1。
  • 如果元素是一个数字且大于零,则它应该为总和加1。
  • 如果元素为0或不是数字,那么它应该为总和加0。

这是我的代码,但无论传入的参数如何都返回0:

(defun sigsum (L)
  (let ((sum 0))                   ;;variable sum
  (if (not (listp L))              ;;if L is not a list
      nil                          ;;return nil
      (dotimes (i (length L))      ;;otherwise loop through L
        (if (numberp (elt L i))    ;;if each element is a number
            (if (< (elt L i) 0)    ;;if is less than 0 subtract 1 from sum
                (- sum 1)
            (if (> (elt L i) 0)    ;;if greater than 0 add 1 to sum
                (+ sum 1))
            (+ sum 0))             ;;else add 0 to sum
          (+ sum 0)))              ;;not a number so add 0 to sum
  )
  sum)                             ;;return sum
)

与往常一样,非常感谢任何帮助。

4 个答案:

答案 0 :(得分:3)

其他答案描述了代码中的问题,但查看解决问题的其他方法可能会有所帮助。这是具有键功能减少的典型情况(参见reduce)。您可以使用(缩减&#39; +列表)来总结列表中的元素。但是,您不想只是总结元素,其中一些可能不是数字,您想要将每个元素映射到数字(-1,0或1),然后添加它们。这意味着你需要一个关键功能。首先,让我们定义将元素取为-1,0或1的函数:

(defun to-number (x)
  (cond
    ((and (numberp x) (< x 0)) -1)
    ((and (numberp x) (> x 0)) 1)
    ((or (not (numberp x)) (zerop x)) 0)))

然后你的总和函数需要返回 nil ,如果它的参数不是列表,或者(减少&#39; + ...:键&#39 ; to-number)如果它的参数是一个列表:

(defun sum (thing)
  (if (not (listp thing))
      nil
      (reduce '+ thing :key 'to-number)))

从概念上讲,这种方法与添加运算符应用于(mapcar&#39; to-number list)的结果相同,但减少通常是首选,因为可以调用函数的最大参数数量,因此(apply&#39; +(mapcar ...))会在时中断( mapcar ...)返回一个比这长的列表。另一个问题是 mapcar 会分配一个全新的列表来保存中间值( to-number 的结果),这是一个不必要的空间使用。

答案 1 :(得分:2)

表达式(+ sum 1) 返回sum多一个。它不会改变sum。您可以使用incfdecf来修改地点。

您也可以使用loop

(loop :for element :in list
      :count (and (numberp element) (plusp element)) :into plus
      :count (and (numberp element) (minusp element)) :into minus
      :finally (return (- plus minus)))

Signum也很有用,但它有浮动传染(如果任何数字都是浮点数,结果也是浮点数。)

(loop :for element :in list
      :when (numberp element)
      :sum (signum element))

答案 2 :(得分:2)

(- sum 1)不会更新任何变量。由于你不使用结果它会消失。就像这是所有编程语言。 Algol语言中的sum + 1(如C)不会更新sum

如果您想更新变量,可以使用setf

(setf sum (+ sum 1))
(setf sum (- sum 1))

或者您可以使用扩展为与上述表达式相同的宏的incfdecf

在CL中还有很多其他方法可以做到。您可以使用reduce

(defun mysignum (list)
  (if (listp list)
      (reduce (lambda (e acc)
                (+ acc
                   (cond ((or (not (numberp e)) (zerop e)) 0)
                         ((< e 0) -1)   
                         (t 1))))
              list)
       nil))

你可以使用循环:

(defun mysignum (list)
  (if (listp list)
      (loop :for e :in list
        :when (and (numberp e) (< e 0))
           :summing -1
        :end
        :when (and (numberp e) (> e 0))
           :summing +1
        :end)
       nil))

答案 3 :(得分:1)

(defun discrete (lis)
 (cond
  ((and (listp lis) (not (equal lis nil)))
   (let ((sum 0))
    (loop for item in lis do
     (cond ((or (not (numberp item)) (equal 0 item)) t)
      ((and (numberp item) (> item 1)) (setf sum (+ 1 sum)))
      ((and (numberp item) (< item 1)) (setf sum (- sum 1)))))
    sum))))

用法:(discrete '(-1 2 3 0 2 2 -1 2 34 0 -1)) =&GT; 3

(discrete '(-4 a b)) =&GT; -1

(discrete '()) =&gt; NIL

(discrete '(a s d f)) =&GT; 0