尝试从第二个列表中删除第一个列表中指定的原子重复项

时间:2011-10-04 06:17:50

标签: list recursion lisp common-lisp

我正在尝试编写一个像remove-duplicates一样的函数,但是它需要两个列表作为输入,第一个指定不允许复制的字符,第二个是各种原子的列表,被修剪。

目前我有这个:

(defun like-remove-duplicates (lst1 lst2)
(if(member (first lst1) lst2)
    (remove-if #'(lambda (a b)
          (equals a b))lst1 lst2)))

我知道这不是正确的,但我无法弄清楚我需要做什么才能执行此功能。我知道我基本上需要检查list1中的第一项是否在list2中,如果是,则删除它的重复项(但保留一项),然后转到第一个列表中的下一项。我设想了递归,但结果并不好。我尝试过研究,但无济于事。

任何帮助?

3 个答案:

答案 0 :(得分:3)

CL-USER> (defun remove-duplicates-from-list (forbidden-list list)
           (reduce (lambda (x y)
                     (let ((start (position y x)))
                       (if start
                           (remove y x :start (1+ start))
                           x)))
                   forbidden-list
                   :initial-value list))
REMOVE-DUPLICATES-FROM-LIST

CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2))
(1 2 3)
CL-USER> (remove-duplicates-from-list '(1 2) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(1 2 1 3 2 4))
(1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 1 2 1 3 2 4))
(0 1 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 3 2 4))
(0 2 3 4)
CL-USER> (remove-duplicates-from-list '(2 1) '(0 2 2 3 4))
(0 2 3 4)

递归由reduce执行(因为这里我们有最常见的递归模式:将前一次迭代的结果提供给下一次)并且remove在{{1}的帮助下完成}参数,即第一次遇到(由:start找到)当前被删除的值之后的偏移量。

如果未找到该值并且position返回position,则说明此案例也很重要。

答案 1 :(得分:2)

这样的事情应该有效并且具有可接受的时间复杂性(以牺牲太空复杂性为代价)。

(defun like-remove-duplicates (only-once list)
  "Remove all bar the first occurence of the elements in only-once from list."
  (let ((only-once-table (make-hash-table))
        (seen (make-hash-table)))
    (loop for element in only-once
     do (setf (gethash element only-once-table) t))
    (loop for element in list
     append (if (gethash element only-once-table)
                (unless (gethash element seen)
                  (setf (gethash element seen) t)
                  (list element))
              (list element)))))

这使用了两个状态表,两个状态表都以元素列表的大小为限,只包含一次,并且在两个列表的长度之和上应该大致为线性。

答案 2 :(得分:0)

(defun remove-listed-dups (a b)
  (reduce (lambda (x y) (if (and (find y a) (find y x)) x (cons y x)))
          b :initial-value ()))