我试图获得两个列表的共同元素。
我已经尝试了可用的交集功能和我自己实现的功能,在尝试在(a a ... a)
和(a b c d ... z)
等列表上测试它们时,两者都给出了相同的奇怪结果。
每当第一个列表只包含多个相同的元素,第二个列表以该元素开头时,结果就是第一个列表。
例如:(intersection '(2 2 2 2) '(2 2 2 3))
返回(2 2 2 2)
我实施的交叉路口:
(defun presentp (a l)
(cond ((null l) nil)
((and (atom (car l)) (equal a (car l))) t)
((not (atom (car l))) (presentp a (car l)))
(t (presentp a (cdr l)))))
(defun intersectionp (a b)
(cond ((not (and a b)) nil)
((presentp (car a) b) (append (list (car a)) (intersection (cdr a) b)))
(t (intersection (cdr a) b))))
如何在该类型的列表上获得良好的结果?例如,我希望来自(2 2 2)
的{{1}}。
答案 0 :(得分:4)
您需要从b
列表中删除匹配项。当您在(2 2 2 3)
中找到2时,您应继续(2 2 3)
作为b
。
此外.. (append (list x) result-list)
与(cons x result-list)
相同,只是CPU周期相同或更少。
(defun intersection (a b)
(cond ((not (and a b)) nil)
((presentp (car a) b)
(cons (car a)
(intersection (cdr a)
(remove (car a) b :count 1))))
(t (intersection (cdr a) b))))
答案 1 :(得分:3)
已经有一个已接受的答案,但我想指出实现提供的答案,其中
(cl:intersection '(2 2 2 2) '(2 2 2 3))
;=> (2 2 2 2)
正确无误。重要的是要认识到交集,nintersection等旨在与被视为集合的列表一起使用。从概念上讲,一个集合没有重复的元素(因为你需要一个 multiset ),所以列表(2),(2 2),(2 2 2)等都代表了同一套,{2}。
14.1.2.2 Lists as Sets
列表有时通过考虑其元素被视为集合 无序的,并假设没有重复的元素。
adjoin nset-difference set-difference union intersection nset-exclusive-or set-exclusive-or nintersection nunion subsetp
图14-5。一些与集合相关的已定义名称。
现在,关于“假设没有元素重复”的那一点实际上意味着你可能不应该使用带有像(2 2 2 2)这样的列表的set函数,因为它有明显的元素重复。即便如此,如果您认为像(2 2 2)和(2 2 2 2)这样的列表代表相同的集,您可以看到intersection
实际上正在为您提供正确的设置。我认为规范实际上要求结果将有三个或四个元素。来自intersection上的HyperSpec条目:
交叉操作描述如下。尽可能 有序对由list-1中的一个元素和一个元素组成 从list-2,:test或:test-not用于确定它们是否存在 满足测试。第一个参数:test或:test-not function是list-1的一个元素;第二个参数是一个元素 表2。如果:不提供test或:test-not,则使用eql。它是一个 错误if:test和:test-not在同一个函数调用中提供。 ...
对于满足测试的每一对,恰好是两个元素中的一个 该对将被放入结果中。两个列表中都没有元素 出现在不满足元素测试的结果中 从另一个清单。如果其中一个列表包含重复元素, 结果可能有重复。
因此,对于(2 2 2 2)
和(2 2 2 3)
,需要考虑16对:
(2 2) (2 2) (2 2) (2 3) ; first element is first 2 from list-1, second elements are from list-2
(2 2) (2 2) (2 2) (2 3) ; first element is second 2 from list-1, second elements are from list-2
(2 2) (2 2) (2 2) (2 3) ; first element is third 2 from list-1, second elements are from list-2
(2 2) (2 2) (2 2) (2 3) ; first element is fourth 2 from list-1, second elements are from list-2
因为“对于满足测试的每一对,两个元素中只有一个将被放入结果中,”在我看来,你最终将会在结果中3到4 2之间,因为你有12对满足测试,你需要覆盖这12对中的每一行和每列。我想,这取决于“对这两个元素中的一个元素中的一个将被置于结果中”的解释。但一般情况下,如果你有,例如,list-as-sets (a1 a2)
和(b1 b2 b3)
那么你就有了这些对:
(a1 b1) (a1 b2) (a1 b3)
(a2 b1) (a2 b2) (a2 b3)
我认为该规范应该被理解为每个ai
和bi
最多只包含一次,并且您永远不会包含给定的{{1 }}和ai
基于特定的对bi
。因此,如果从第一行开始选择(ai bi)
并在结果中包含(a1 b2)
,则剩余的可以为结果提供元素的对是
b2
如果您从(a1 b1) (a1 b3)
(a2 b1) (a2 b3)
获取了a1
,那么剩余的对将是
(a1 b2)
也就是说,当您从其中一对中包含元素时,您要么从确定可能结果的对表中删除行或列。在第一种情况下,您仍然可以在结果中添加两个元素,但在第二种情况下,可能会有三个元素。
事实上,在LispWorks中,如果颠倒参数的顺序,你将得到3元素版本:
(a2 b1) (a2 b2) (a2 b3)
无法保证结果中元素的顺序 以任何特定方式反映参数的顺序。该 结果列表可以与list-1或list-2共享单元格,或者与list-1或list-2共享单元格 如果合适的话。
你没有提到你是否只是获得一个等效的列表,或者你是否真的得到了list-1。在Lispworks中,似乎你实际上得到了相同的列表,尽管这不是必需的:
CL-USER 5 > (intersection '(2 2 2 3) '(2 2 2 2))
(2 2 2)
答案 2 :(得分:0)
这是我的运作良好。我使用删除来删除重复的符号。
sender.tag