如何将玩偶的结果保存在新列表中?

时间:2017-06-28 21:09:39

标签: lisp common-lisp

我想删除两个给定列表中不包含的元素。

我正在尝试的代码是:

(defun remove_odd_ones(L1 L2)
    (cond ((or (null L1) (null L2)) nil)
           ((dolist (x L2) (if (not(member x L1)) (remove x L2))))))


(remove_odd_ones '(a b c c e k) '(a b c p d d n))

我期待的是:(a b c c)

我收到的结果:NIL

我可以使用什么功能来保存dolist会导致新列表?

1 个答案:

答案 0 :(得分:0)

  

(remove_odd_ones '(a b c c e k) '(a b c p d d n))

     

我期待的是:(a b c c)

这称为“集合交集”:

Lisp> (intersection '(a b c c e k) '(a b c p d d n))
(A B C C)

我们如何能够(效率低下)自己做到这一点:

(defun our-intersection (l1 l2)
  (mapcan (lambda (l1-item)
            (if (member l1-item l2)
              (list l1-item)))
          l1))

映射l1,收集l2中的元素。

dolist功能对此并不好,因为它不具备功能性/适用性;这是一个势在必行的循环小工具。如果您想使用dolist收集结果列表,则必须在身体中执行操作,并借助其他变量:

(defun our-intersection (l1 l2)
  (let ((out nil))
    (dolist (l1-item l1 out)
      (when (member l1-item l2)
        (push l1-item out)))))

我们定义一个变量out,它最初包含空列表。我们dolist遍历l1,依次将变量l1-item设置为每个元素。如果l1-item中出现l2,则会将其推送到out列表中:

Lisp> (our-intersection '(a b c c e k) '(a b c p d d n))
(C C B A)

dolist至少让我们指定vi的第三个参数,表达式将生成表单的结果值:这就是我们放置对out的引用的位置。

要按(A B C C)顺序获取,我们可以使用nreverse调用替换该引用,如下所示:

(dolist (l1-item l1 (nreverse out))
  ... )

这是列表上的Common Lisp过程编程中的常见模式:通过推送到新的本地列表来累积结果,然后在返回之前用nreverse破坏性地反转它。 (这是安全的,因为列表是由程序代码在本地分配的:程序中没有任何其他内容知道列表,直到返回,因此破坏性重新安排不会影响任何其他功能或模块。)