List 返回和的Lisp函数
我正试图写一个奇怪的函数,所以请耐心听我说。此函数应将列表List 返回和的Lisp函数,list,sum,lisp,iteration,clisp,List,Sum,Lisp,Iteration,Clisp,我正试图写一个奇怪的函数,所以请耐心听我说。此函数应将列表L作为参数,并具有sum变量。如果L不是列表,它应该返回nil。否则,它应该遍历列表的每个元素,并执行以下操作: 如果元素是一个数字且小于零,则应从和中减去1 如果元素是一个数字且大于零,则应在总和上加1 如果元素为0或不是数字,则应将0添加到总和中 下面是我的代码,但不管传入的参数如何,它都返回0: (defun sigsum (L) (let ((sum 0)) ;;variable sum
L
作为参数,并具有sum
变量。如果L
不是列表,它应该返回nil
。否则,它应该遍历列表的每个元素,并执行以下操作:
- 如果元素是一个数字且小于零,则应从和中减去1
- 如果元素是一个数字且大于零,则应在总和上加1
- 如果元素为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
)
(定义sigsum(L)
(设((和0));;变量和
如果我不是一个列表
零;返回零
(dotimes(i(长度L));否则通过L循环
如果每个元素都是一个数字
(如果(<(elt L i)0);;如果小于0,则从和中减去1
(-和1)
(如果(>(elt L i)0);;如果大于0,则加1求和
(+总和1))
(+sum 0));否则加0到sum
(+sum 0));;不是一个数字,所以给sum加上0
)
总数;返回总数
)
一如既往,我们非常感谢您的帮助。表达式(+sum 1)
比sum
返回一个以上的值。它不会更改总和
。您可以使用修改位置的incf
或decf
获得所需位置
您还可以使用循环:
(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
也很有用,但它具有浮点传染(如果其中任何一个数字是浮点,结果也将是浮点)
(-sum 1)
不更新任何变量。因为你不使用结果,它就消失了。这就像是所有的编程语言sum+1
不会更新sum
如果要更新变量,可以使用setf
:
(setf sum (+ sum 1))
(setf sum (- sum 1))
或者您可以使用incf
和decf
这两个宏,它们是扩展到与上述表达式相同的宏
在CL中还有很多其他的方法,你可以使用reduce
(解除mysignum(列表)
(如果(列表列表)
(减少(λ)(e acc)
(+acc)
(cond((或(非(numberp e))(zerope))0)
(
您可以使用循环:
(解除mysignum(列表)
(如果(列表列表)
(循环:用于列表中的e:
:何时(和(数字e)(e 0))
:求和+1
(完)
(零)
其他答案描述了代码中的问题,但看看其他解决问题的方法可能会有所帮助。这是使用键函数进行缩减的一个非常典型的例子(请参阅)。您可以使用(reduce'+list)对列表中的元素进行汇总。但是,您不希望只对元素进行求和(其中一些元素可能不是数字),而是希望将每个元素映射到一个数字(-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)))
从概念上讲,这种方法与将加法运算符应用于(mapcar'到数字列表)的结果相同,但通常首选reduce,因为函数可以使用最大数量的参数调用,因此(如果(mapcar…)应用“+(mapcar…)会中断返回的列表比该列表长。另一个问题是,mapcar将分配一个全新的列表来保存中间值(将的结果分配给编号),这是一种不必要的空间使用。(defun discrete(lis)
(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))))
(续)
((和(listp lis)(不等于lis nil)))
(让((和0))
(lis do中项目的循环)
(条件((或(非(数字项))(等于0项))t)
((和(编号项目)(>项目1))(setf总和(+1总和)))
((和(编号项目)(<项目1))(setf总和(-总和1()))
总数))
用法:(离散'-12302-12340-1))
=>3
(离散'-4ab))
=>-1
(离散'())
=>零
(离散(a s d f))
=>0好的解决方案。您可以将(if(not(listp thing))…)替换为(when(listp thing)(reduce…),以使其更简洁。@DanielKochmański它会更简洁,但不那么明确。我认为它归结为首选样式。我倾向于在做有副作用的事情时使用(例如,(when(minusp x)(setf x(-x))
)我知道(when nil…
的值被明确定义为nil
,但是看到(defun foo…(when…)
让我觉得foo
的返回值应该是可忽略的,而不是它应该总是“空列表或一个数字”,其中as(如果…’()(减少“+…))
更清楚地说是一个空列表或数字。我想你对首选样式的看法是对的。很抱歉这么挑剔。@DanielKochmański并非所有;我并不声称我首选的样式在任何客观方面都是正确的;这只是我个人的偏好。我受到了纯函数式编程的一些影响,所以我觉得不能这样做很有吸引力o说“这个函数的输入可以是任何东西;如果它不是一个列表,则返回空列表;如果输入是一个列表,则结果是…”。我喜欢这个函数几乎是分段定义的。
(defun sum (thing)
(if (not (listp thing))
nil
(reduce '+ thing :key 'to-number)))
(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))))