我正在尝试编写一个像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中,如果是,则删除它的重复项(但保留一项),然后转到第一个列表中的下一项。我设想了递归,但结果并不好。我尝试过研究,但无济于事。
任何帮助?
答案 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 ()))