我有一个深度嵌套的列表,我想删除列表中出现的所有元素。我有这段代码:
(defn eliminate [value lst]
(defn sub-eliminate [lst]
(def currentItem (first lst))
(if-not (empty? lst)
(if (seq? currentItem)
(cons (sub-eliminate currentItem) (sub-eliminate (rest lst)))
(if (= value currentItem)
(sub-eliminate (rest lst))
(cons currentItem (sub-eliminate (rest lst)))
)
)
'()
)
)
(sub-eliminate lst)
)
但是,它并没有在内层删除。为什么?
答案 0 :(得分:2)
我的猜测是你使用矢量作为序列。
(eliminate 3 [3 3])
;()
(eliminate 3 [3 [3]])
;([3])
如果你向我们展示了一个例子,那将是微不足道的:tut,tut!
发生了什么事?
虽然矢量是可选的,但它们不是序列:
(seq? [])
;false
在外层,您将lst
视为序列,因此first
和rest
可以正常工作,因为它们将参数包装在隐式seq
中。但是seq?
将在任何立即封闭的向量上失败,并且甚至不会看到那些向内的向量。
如果您将seq?
替换为sequential?
,则列表和向量将起作用。
(sequential? [])
;true
正如@noisesmith指出的那样,更严重的是你在内部范围内使用def
和defn
。将其替换为let
或letfn
。
你也可以改善你的风格:
(if-not (empty? lst) ... )
替换为(if (seq lst) ...)
。cond
展平您的嵌套if
。这需要反转
(1)中的测试,因此不需要它。 recur
作为尾部递归情况,找到value
,如
@Mark确实如此。如果您不想看到结果,请立即离开:
(defn eliminate [value lst]
(letfn [(sub-eliminate [lst]
(let [current-item (first lst)]
(cond
(empty? lst) '()
(sequential? current-item) (cons (sub-eliminate current-item)
(sub-eliminate (rest lst)))
(= value current-item) (recur (rest lst))
:else (cons current-item (sub-eliminate (rest lst))))))]
(sub-eliminate lst)))
还有一个招标点:
(first lst)
不为空之前,您会调用lst
。没有
伤害已经完成:你只会得到nil
,你忽略了。 使用解构的替代Apporach
您经常可以使用destructuring来缩短序列的递归处理。我倾向于表达你的功能:
(defn eliminate [x xs]
((fn rem-x [xs]
(if-let [[y & ys] (seq xs)]
(if (= x y)
(recur ys)
(cons
(if (sequential? y) (rem-x y) y)
(rem-x ys)))
()))
xs))
答案 1 :(得分:1)
为了学习,请看一下这个功能:
(define rember*
(lambda (x l)
(cond ((null? l) '())
((atom? (car l))
(if (eq? (car l) x)
(rember* x (cdr l))
(cons (car l)
(rember* x (cdr l)))))
(else (cons (rember* x (car l))
(rember* x (cdr l)))))))
这是一本关于“The Little Schemer”的简单递归函数,它是学习如何编写这类递归函数的好资源。
让我们看看我们是否可以将其翻译成Clojure:
(defn rember* [x l]
(cond (empty? l) '()
(seq? (first l)) (cons (rember* x (first l))
(rember* x (rest l)))
:else (if (= (first l) x)
(recur x (rest l))
(cons (first l)
(rember* x (rest l))))))
user> (rember* 'x '((x y) x (z (((((x))))))))
;; => ((y) (z ((((()))))))
答案 2 :(得分:1)
(defn expel [victim xs]
(mapcat (fn [x]
(cond
(sequential? x) [(expel victim x)]
(= x victim) []
:else [x]))
xs))