我需要加入两个列表,对它们进行排序并删除重复项。有一个更好的方法吗?

时间: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用于测试"这些重复是否被视为")。