我需要加入两个列表,对它们进行排序并删除重复项。有一个更好的方法吗?
时间:2020-03-06 14:24:54 来源:igfitidea点击:
我有两个未排序的列表,我需要生成另一个已排序且所有元素都是唯一的列表。
这两个列表中的元素可以出现多次,并且它们最初是未排序的。
我的函数看起来像这样:
(defun merge-lists (list-a list-b sort-fn) "Merges two lists of (x, y) coordinates sorting them and removing dupes" (let ((prev nil)) (remove-if (lambda (point) (let ((ret-val (equal point prev))) (setf prev point) ret-val)) (sort (merge 'list list-a list-b sort-fn) ;' sort-fn))))
有没有更好的方法可以达到相同目的?
样品通话:
[CL]> (merge-lists '(9 8 4 8 9 7 2) '(1 7 3 9 2 6) #'>) ==> (9 8 7 6 4 3 2 1)
解决方案
我想我首先要对两个列表分别进行排序,然后将它们与一个也可以跳过重复项的函数合并。这应该更快一些,因为它需要遍历两个列表的次数减少。
附注:我怀疑这样做的速度会更快,因为我们基本上总是需要至少一种分类和一种合并。也许我们可以将两者结合在一个函数中,但是如果那没有太大的不同,我也不会感到惊讶。
听起来好像我们需要使用Sets。
我们邻里友好的Lisp专家指出了删除重复功能。
他还提供了以下代码段:
(defun merge-lists (list-a list-b sort-fn test-fn) (sort (remove-duplicates (append list-a list-b) :test test-fn) sort-fn))
如果在合并之前对列表进行了排序,则可以同时合并,重复删除和排序它们。如果对它们进行了排序且无重复,那么合并/排序/重复删除功能将变得非常简单。
实际上,最好更改插入功能,以便它执行排序插入以检查重复项。这样一来,我们始终可以对不含重复项的列表进行排序,并且将它们合并是一件小事。
再说一遍,我们可能更喜欢具有快速插入功能,但稍后会以排序/删除重复项为代价。
如果在删除重复项之前应用排序,删除重复项功能是否会运行得更好?
正如Antti所指出的,尽管我可能会为测试功能使用关键字(或者可选参数),但我们可能想利用REMOVE-DUPLICATES和SORT:
(defun merge-lists(list-1 list-2 sort-fn&key(test#'eql))
...)
或者
(defun merge-lists(list-1 list-2 sort-fn&optional(测试#'eql)
...)
这样,除非EQL不够好,否则我们不必指定测试功能(由REMOVE-DUPLICATES用于测试"这些重复是否被视为")。