删除 nil 不会转到列表中的最后一个元素
Removing nil not going to the last element in the list
所以我有一个任务,我必须在不使用 common lisp 中的 remove 函数的情况下从列表中删除 nils。除了没有打印出其中一个列表中的最后一个元素外,我大部分时间都在使用它。
我有:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L)) (OR (removeNILMost(car L)) (removeNILMost(cdr L))))
((not (eq nil (car L))) (cons (car L) (removeNILMost(cdr L))))
(T (removeNILMost(cdr L)))
)
)
输出:
;;; #2 removeNILMost
(removeNILMost '(NIL X NIL NIL Y NIL Z))
(X Y Z)
(removeNILMost '(X NIL (Y NIL Z) NIL))
(X Y Z)
(removeNILMost '(NIL (NIL) (X NIL Y) (NIL NIL) Z))
(X Y)
(removeNILMost '(NIL ( (((((NIL) NIL)))))))
NIL
第一个问题是倒数第二个输出,它应该是 (x Y Z)。
首先,让我们稍微清理一下格式,以便于阅读。请注意,在自己的行中留下悬垂的括号在 lisps 中非常 un-idiomatic;毕竟这不是 curly-braces 语言:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L))
(OR (removeNILMost (car L))
(removeNILMost (cdr L))))
((not (eq nil (car L)))
(cons (car L)
(removeNILMost (cdr L))))
(T
(removeNILMost (cdr L)))))
现在,为什么要使用 or
来组合对 removeNILMost
的两次递归调用的结果?因为 or
是 short-circuiting,当 both 是 non-empty 调用对列表时,只返回第一个结果:
(OR (removeNILMost (car L))
(removeNILMost (cdr L))))
这不是预期的结果,这也是 (removeNILMost '(nil (nil) (x nil y) (nil nil) z))
中缺少最终 z
的原因。
现在,由于 removeNILMost
returns 一个列表,append
是组合这些结果以给出 (removeNILMost '(X NIL (Y NIL Z) NIL))
的 OP 结果的适当函数 --> (X Y Z)
.这里的目标必须是展平输入列表并从中删除所有 nil
。此更改将“修复”OP 发布的代码:
(append (removeNILMost (car L))
(removeNILMost (cdr L))))
如果目标只是从输入中移除nil
s,那么应该保留输入列表的树结构。例子 没有 显示这一点,但我怀疑正确的实现会给出:
CL-USER> (removeNILMost '(X NIL (Y NIL Z) NIL))
(X (Y Z))
为了保留列表的结构,条件可以在使用第二个结果之前检查第一个结果是否为 nil
:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L))
(let ((left (removeNILMost (car L)))
(right (removeNILMost (cdr L))))
(if left
(cons left right)
right)))
((not (eq nil (car L)))
(cons (car L)
(removeNILMost (cdr L))))
(T
(removeNILMost (cdr L)))))
下面的代码稍微清理了上面的代码;请注意 kebab-case
在 lisp 中优于 camelCase
的变体。对测试进行了一些重组,使逻辑更加清晰。
(defun remove-all-nils (L)
(cond ((null L) '()) ; empty list input remains empty
((null (car L)) ; if the first element is NIL, just move on
(remove-all-nils (cdr L)))
((listp (car L)) ; if the first element is a list...
(let ((left (remove-all-nils (car L)))
(right (remove-all-nils (cdr L))))
(if left ; conditionally CONS the results together
(cons left right)
right)))
(t ; otherwise the first element is not a list
(cons (car L) ; so CONS it to the result of processing the remainder
(remove-all-nils (cdr L))))))
以下是一些示例交互:
CL-USER> (remove-all-nils '(nil x nil nil y nil z))
(X Y Z)
CL-USER> (remove-all-nils '(x nil (y nil z) nil))
(X (Y Z))
CL-USER> (remove-all-nils '(nil (nil) (x nil y) (nil nil) z))
((X Y) Z)
CL-USER> (remove-all-nils '(nil a (b (c nil (nil) d) e (nil f g (h nil i (nil j (nil nil) k) l nil m) n ) o p q) r nil))
(A (B (C D) E (F G (H I (J K) L M) N) O P Q) R)
CL-USER> (remove-all-nils '(nil ((nil (nil)) (nil (nil (nil (nil nil)) nil))) nil))
NIL
所以我有一个任务,我必须在不使用 common lisp 中的 remove 函数的情况下从列表中删除 nils。除了没有打印出其中一个列表中的最后一个元素外,我大部分时间都在使用它。
我有:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L)) (OR (removeNILMost(car L)) (removeNILMost(cdr L))))
((not (eq nil (car L))) (cons (car L) (removeNILMost(cdr L))))
(T (removeNILMost(cdr L)))
)
)
输出:
;;; #2 removeNILMost
(removeNILMost '(NIL X NIL NIL Y NIL Z))
(X Y Z)
(removeNILMost '(X NIL (Y NIL Z) NIL))
(X Y Z)
(removeNILMost '(NIL (NIL) (X NIL Y) (NIL NIL) Z))
(X Y)
(removeNILMost '(NIL ( (((((NIL) NIL)))))))
NIL
第一个问题是倒数第二个输出,它应该是 (x Y Z)。
首先,让我们稍微清理一下格式,以便于阅读。请注意,在自己的行中留下悬垂的括号在 lisps 中非常 un-idiomatic;毕竟这不是 curly-braces 语言:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L))
(OR (removeNILMost (car L))
(removeNILMost (cdr L))))
((not (eq nil (car L)))
(cons (car L)
(removeNILMost (cdr L))))
(T
(removeNILMost (cdr L)))))
现在,为什么要使用 or
来组合对 removeNILMost
的两次递归调用的结果?因为 or
是 short-circuiting,当 both 是 non-empty 调用对列表时,只返回第一个结果:
(OR (removeNILMost (car L))
(removeNILMost (cdr L))))
这不是预期的结果,这也是 (removeNILMost '(nil (nil) (x nil y) (nil nil) z))
中缺少最终 z
的原因。
现在,由于 removeNILMost
returns 一个列表,append
是组合这些结果以给出 (removeNILMost '(X NIL (Y NIL Z) NIL))
的 OP 结果的适当函数 --> (X Y Z)
.这里的目标必须是展平输入列表并从中删除所有 nil
。此更改将“修复”OP 发布的代码:
(append (removeNILMost (car L))
(removeNILMost (cdr L))))
如果目标只是从输入中移除nil
s,那么应该保留输入列表的树结构。例子 没有 显示这一点,但我怀疑正确的实现会给出:
CL-USER> (removeNILMost '(X NIL (Y NIL Z) NIL))
(X (Y Z))
为了保留列表的结构,条件可以在使用第二个结果之前检查第一个结果是否为 nil
:
(defun removeNILMost (L)
(cond ((NULL L) NIL)
((listp (car L))
(let ((left (removeNILMost (car L)))
(right (removeNILMost (cdr L))))
(if left
(cons left right)
right)))
((not (eq nil (car L)))
(cons (car L)
(removeNILMost (cdr L))))
(T
(removeNILMost (cdr L)))))
下面的代码稍微清理了上面的代码;请注意 kebab-case
在 lisp 中优于 camelCase
的变体。对测试进行了一些重组,使逻辑更加清晰。
(defun remove-all-nils (L)
(cond ((null L) '()) ; empty list input remains empty
((null (car L)) ; if the first element is NIL, just move on
(remove-all-nils (cdr L)))
((listp (car L)) ; if the first element is a list...
(let ((left (remove-all-nils (car L)))
(right (remove-all-nils (cdr L))))
(if left ; conditionally CONS the results together
(cons left right)
right)))
(t ; otherwise the first element is not a list
(cons (car L) ; so CONS it to the result of processing the remainder
(remove-all-nils (cdr L))))))
以下是一些示例交互:
CL-USER> (remove-all-nils '(nil x nil nil y nil z))
(X Y Z)
CL-USER> (remove-all-nils '(x nil (y nil z) nil))
(X (Y Z))
CL-USER> (remove-all-nils '(nil (nil) (x nil y) (nil nil) z))
((X Y) Z)
CL-USER> (remove-all-nils '(nil a (b (c nil (nil) d) e (nil f g (h nil i (nil j (nil nil) k) l nil m) n ) o p q) r nil))
(A (B (C D) E (F G (H I (J K) L M) N) O P Q) R)
CL-USER> (remove-all-nils '(nil ((nil (nil)) (nil (nil (nil (nil nil)) nil))) nil))
NIL