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的元素)。