基本 Lisp 函数 - 偶数和减去奇数和
Basic Lisp function - sum of even minus sum of odd
我正在尝试编写一个函数,它将 List
作为参数并计算 sum of even numbers
减去 sum of odd numbers
。
这是我的实现,但我不知道为什么它没有按预期工作,你能给我任何关于错误的提示吗?
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (CAR R) (sumEvenOdd (CDR R))))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (CAR R) (sumEvenOdd (CDR R)) ))
((LISTP (CAR R)) (sum (sumEvenOdd (CAR R)) (sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))
)
)
关于代码算法,它失败了,因为数学是如何完成的。
现在的代码是这样的,这个对列表 (list 1 2 3 4 5) 进行的评估是 (- 1 (+ 2 (- 3 (+ 4 (- 5 0))))) 等于 5。
我们期望的是 (2+4)-(1+3+5) 等于 -3。怎么了?
基本上数学中的加法运算是可交换的,而减法运算则不是。 1+5和5+1是一样的。 1-5 和 5-1 不是。
这反映了最后一个操作的代码,其中 5 被减去 0。
最简单的解决方案是调整操作顺序,切换参数。
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R)))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R)))
)
)
这样计算将是:(- (+ (- (+ (- 0 1) 2) 3) 4) 5) 等于 -3。
PS:您可以在此处检查和测试代码:http://goo.gl/1cEA5i
你快到了。这是您的代码的编辑版本:
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R))
(= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R))) ; switched places for consistency
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R))) ; operands needed to be switched
((LISTP (CAR R)) (+ (sumEvenOdd (CAR R)) ; what is sum? replaced with +
(sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))))
这是一个使用 reduce 的解决方案:
(defun sum-even-odd (list)
(reduce (lambda (acc e)
(cond ((consp e) (+ acc (sum-even-odd e)))
((not (numberp e)) acc) ; perhaps not needed
((oddp e) (- acc e))
(t (+ acc e))))
list
:initial-value 0))
(sum-even-odd '(1 2 (3 4 (5 6) 7) 8 9 10)) ; ==> 5
如果您确定该列表只有数字或其他带有数字的列表,则检查不是 consp
或 numberp
的内容将是多余的。这不适用于点列表。
有关于如何修复代码的答案,但让我们看一下不同的实现。
您没有指定您的函数需要在树上工作,所以这是一个简单的数字列表。
(defun sum-even-odd (r)
(- (apply #'+ (remove-if-not #'evenp r))
(apply #'+ (remove-if-not #'oddp r))))
remove-if-not
采用列表和谓词函数。它 运行 列表中每个元素的谓词,并创建一个新列表,只包含谓词没有 return nil 的元素。
apply
接受一个函数和一个列表,并调用函数,参数是列表的元素。所以 (apply #'+ '(1 2 3 4))
等同于 (+ 1 2 3 4)
Common lisp 具有处理列表(和许多其他数据类型)的良好功能,检查它们,您的代码最终会变得更加清晰。
也不要在常见的 lisp 中使用驼峰式大小写(或任何基于大小写的命名),并且符号不区分大小写。符号HeLloThErE
和hellothere
和helloThere
是相同的符号。这就是您会在名称中看到连字符的原因。
我正在尝试编写一个函数,它将 List
作为参数并计算 sum of even numbers
减去 sum of odd numbers
。
这是我的实现,但我不知道为什么它没有按预期工作,你能给我任何关于错误的提示吗?
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (CAR R) (sumEvenOdd (CDR R))))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (CAR R) (sumEvenOdd (CDR R)) ))
((LISTP (CAR R)) (sum (sumEvenOdd (CAR R)) (sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))
)
)
关于代码算法,它失败了,因为数学是如何完成的。 现在的代码是这样的,这个对列表 (list 1 2 3 4 5) 进行的评估是 (- 1 (+ 2 (- 3 (+ 4 (- 5 0))))) 等于 5。 我们期望的是 (2+4)-(1+3+5) 等于 -3。怎么了? 基本上数学中的加法运算是可交换的,而减法运算则不是。 1+5和5+1是一样的。 1-5 和 5-1 不是。 这反映了最后一个操作的代码,其中 5 被减去 0。
最简单的解决方案是调整操作顺序,切换参数。
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R)) (= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R)))
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R)))
)
)
这样计算将是:(- (+ (- (+ (- 0 1) 2) 3) 4) 5) 等于 -3。
PS:您可以在此处检查和测试代码:http://goo.gl/1cEA5i
你快到了。这是您的代码的编辑版本:
(defun sumEvenOdd (R)
(cond
((NULL R) 0)
((and (ATOM (CAR R))
(= (mod (CAR R) 2) 0))
(+ (sumEvenOdd (CDR R)) (CAR R))) ; switched places for consistency
((and (ATOM (CAR R)) (not (= (mod (CAR R) 2) 0)))
(- (sumEvenOdd (CDR R)) (CAR R))) ; operands needed to be switched
((LISTP (CAR R)) (+ (sumEvenOdd (CAR R)) ; what is sum? replaced with +
(sumEvenOdd (CDR R))))
(T (sumEvenOdd (CDR R)))))
这是一个使用 reduce 的解决方案:
(defun sum-even-odd (list)
(reduce (lambda (acc e)
(cond ((consp e) (+ acc (sum-even-odd e)))
((not (numberp e)) acc) ; perhaps not needed
((oddp e) (- acc e))
(t (+ acc e))))
list
:initial-value 0))
(sum-even-odd '(1 2 (3 4 (5 6) 7) 8 9 10)) ; ==> 5
如果您确定该列表只有数字或其他带有数字的列表,则检查不是 consp
或 numberp
的内容将是多余的。这不适用于点列表。
有关于如何修复代码的答案,但让我们看一下不同的实现。 您没有指定您的函数需要在树上工作,所以这是一个简单的数字列表。
(defun sum-even-odd (r)
(- (apply #'+ (remove-if-not #'evenp r))
(apply #'+ (remove-if-not #'oddp r))))
remove-if-not
采用列表和谓词函数。它 运行 列表中每个元素的谓词,并创建一个新列表,只包含谓词没有 return nil 的元素。
apply
接受一个函数和一个列表,并调用函数,参数是列表的元素。所以 (apply #'+ '(1 2 3 4))
等同于 (+ 1 2 3 4)
Common lisp 具有处理列表(和许多其他数据类型)的良好功能,检查它们,您的代码最终会变得更加清晰。
也不要在常见的 lisp 中使用驼峰式大小写(或任何基于大小写的命名),并且符号不区分大小写。符号HeLloThErE
和hellothere
和helloThere
是相同的符号。这就是您会在名称中看到连字符的原因。