【问题标题】:Lisp list iterationLisp 列表迭代
【发布时间】:2010-09-07 23:12:55
【问题描述】:

我有一个函数,它获取 x(a value) 和 xs(a list) 并从列表中删除所有大于 x 的值。那么它不起作用,你能告诉我为什么吗?

(defun biggerElems(x xs) 
  (let ((xst))
    (dolist (elem xs)
      (if (> x elem)
          (setf xst (remove elem xs))))
    xst))

【问题讨论】:

    标签: lisp list iteration


    【解决方案1】:

    我认为是这条线不对:

    (setf xst (remove elem xs))))
    

    setf 的第一个参数是位置,然后是值。看起来你把它弄反了(xst 要么是 nil 要么是未初始化的)。

    您可能会发现这样做更容易:

    (defun biggerElems (x xs)
      (remove-if (lambda (item) (> item x)) xs))
    

    【讨论】:

      【解决方案2】:

      最简洁的 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))
      

      【讨论】:

        【解决方案3】:

        它是这样工作的:

        (defun filterBig (x xs)
          (remove-if (lambda (item) (> item x)) xs))
        

        “#”是干什么用的?它没有编译。

        【讨论】:

          【解决方案4】:

          如果您想以 Lisp 方式执行此操作,可以使用递归返回新列表:

          (defun biggerElems (x xs)
            (cond ((null xs) NIL)
                  ((< x (car xs))
                   (biggerElems x (cdr xs)))
                 (t
                  (cons (car xs) (biggerElems x (cdr xs))))))
          

          @路易斯·奥利维拉

          此解决方案与问题中发布的解决方案形成对比。如果我们需要做一些稍微复杂一点的事情,重要的是要以递归方法来操作列表。

          【讨论】:

          • 仅仅因为你可以在 Lisp 中使用递归,并不意味着它就是“Lisp 方式”。在 Lisp 中有几种机制可以做到这一点(如这里其他地方所见),它们都是惯用的。递归方法简直是最原始的。
          【解决方案5】:

          @Ben:不是 setf 调用错误——问题是他没有更新 xs。

          ie: xst 被设置为 xs,元素被移除,但 xs 没有被更新。如果要删除第二个元素,则 xst 将包含第一个元素。

          您需要将 xst 绑定到 xs,并将 remove 调用中的 xs 替换为 xst。这将删除所有 x 大于的元素。即:

          (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 可能会稍微快一些(delete 是破坏性的......取决于您的实现,它可能比 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 大于的元素)。

          【讨论】:

            【解决方案6】:

            “#”是干什么用的?它没有 用它编译。

            错字。通常你用#'(比如(remove-if #'oddp list))来引用函数,但是在我编辑的时候,我忘了去掉'#'。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-06-19
              • 1970-01-01
              • 2012-10-11
              • 1970-01-01
              • 2012-10-19
              • 1970-01-01
              • 2019-07-05
              • 1970-01-01
              相关资源
              最近更新 更多