有没有一种有效的方法来合并Lisp中的两个列表,这样如果它们有共同的元素,那么这些元素只会出现在结果列表中一次?
目前,我有以下代码:
(defun divisible-by-5 (num)
(zerop (mod num 5)))
(defun divisible-by-3 (num)
(zerop (mod num 3)))
(remove-if-not #'dividable-by-5 '(loop for i from 1 upto 10 collect i))
(remove-if-not #'divisible-by-3 '(loop for i from 1 upto 10 collect i))
我想以上述方式合并底部表单返回的两个列表,以便合并到其中。
答案 0 :(得分:3)
您已经两次收集列表(1 ... n),然后创建 删除某些元素的新列表,然后进行组合 那些清单。如果你正在寻找有效率,你应该结合起来 生成初始列表和测试以及集合的过程:
-3
但是如果你真的想单独收集列表然后合并 他们,你可以用UNION做到这一点:
(flet ((by-5 (n)
(zerop (mod n 5)))
(by-3 (n)
(zerop (mod n 3))))
(loop for x from 1 to 50
unless (and (by-3 x)
(by-5 x))
collect x))
现在,工会并不能保证保持秩序,但在这种情况下,因为 你知道你的列表已经订购了,你可以合并它们 更有效率,因为你可以比较元素,并知道 在某一点之后,你不会遇到重复:
(flet ((by-5 (n)
(zerop (mod n 5)))
(by-3 (n)
(zerop (mod n 3))))
(let ((fives (loop for x from 1 to 50 unless (by-5 x) collect x))
(threes (loop for x from 1 to 50 unless (by-5 x) collect x)))
(union fives threes)))
以下是其使用示例:
(defun merge-unique (l1 l2 predicate)
"Returns the result of merging L1 and L2, with no duplicates.
L1 and L2 should already be sets (that is, containing no duplicates),
and should be ordered according to PREDICATE. The tail of the result
may be shared with with either L1 or L2."
(labels ((test (x y)
(funcall predicate x y))
(%merge (l1 l2 result)
"Tail recursive merge procedure. This could be converted
to an iterative DO-loop without too much touble."
(cond
((endp l1)
(nreconc result l2))
((endp l2)
(nreconc result l1))
((destructuring-bind (x . xs) l1
(destructuring-bind (y . ys) l2
(cond
((test x y)
(%merge xs l2 (list* x result)))
((test y x)
(%merge l1 ys (list* y result)))
(t
(%merge xs ys (list* x result))))))))))
(%merge l1 l2 '())))