Lisp列表迭代
时间:2020-03-05 18:48:24 来源:igfitidea点击:
我有一个函数,它获取x(一个值)和xs(一个列表),并从列表中删除所有大于x的值。好吧,这行不通,你能告诉我为什么吗?
(defun biggerElems(x xs) (let ((xst)) (dolist (elem xs) (if (> x elem) (setf xst (remove elem xs)))) xst))
解决方案
回答
我认为这是不对的:
(setf xst (remove elem xs))))
setf的第一个参数是位置,后跟值。看起来我们已经倒退了(而xst是nil或者未初始化)。
我们可能会发现这样做更容易:
(defun biggerElems (x xs) (remove-if (lambda (item) (> item x)) xs))
回答
它像这样工作:
(defun filterBig (x xs) (remove-if (lambda (item) (> item x)) xs))
"#"是什么意思?它没有编译。
回答
What was the '#' for? It didn't compile with it.
错别字。通常,我们使用#'来引用函数(例如
((remove-if#'oddp list)`),但是当我进行编辑时,却忘记删除了'#'。
回答
如果要使用Lisp Way进行此操作,则可以使用递归返回新列表:
(defun biggerElems (x xs) (cond ((null xs) NIL) ((< x (car xs)) (biggerElems x (cdr xs))) (t (cons (car xs) (biggerElems x (cdr xs))))))
@Lus Oliveira
此解决方案与问题中发布的解决方案形成对比。如果我们需要做一些稍微复杂的事情,那么扎根于处理列表的递归方法就很重要。
回答
最简洁的AFAIK:
(defun bigger-elements (x xs) (remove x xs :test #'<))
返回一个新列表,它从xs中删除所有元素y
(< y x)
或者使用著名的LOOP:
(defun bigger-elements-2 (x xs) (loop for e in xs unless (< e x) collect e))
回答
@Ben:不是setf调用错了-问题在于他没有更新xs。
即:xst被设置为xs,元素被删除,但是xs没有被更新。如果要删除第二个元素,则xst将具有第一个元素。
我们将需要将xst绑定到xs,并用xst替换remove调用中的xs。然后将删除所有大于x的元素。 IE:
(defun biggerElems(x xs) (let ((xst xs)) (dolist (elem xs) (when (> x elem) (setf xst (remove elem xst)))) xst))
将xst设置为(copy-list xs)可能会稍快一些,然后使用delete而不是remove(删除是破坏性的……根据实现,它可能比remove更快。由于多次调用,一次复制并破坏性地删除列表可能会获得更好的性能)。
或者:
(defun bigger-elems (x xs) ; I prefer hyphen separated to camelCase... to each his own (loop for elem in xs when (<= x elem) collect elem))
回顾原始文章,这有点令人困惑...我们说要删除所有大于x的元素,但是代码看起来像是它试图删除所有大于x的元素。我写的解决方案返回所有大于x的元素(即:删除所有大于x的元素)。