Common Lisp:删除具有相同cdr的元素

时间:2014-12-09 18:30:16

标签: list lisp common-lisp

(分配帮助,对我很轻松)(我必须这样做而不使用破坏性功能(setf))

使用常见的lisp,作为一些代码的一部分,我需要能够:

列出一份清单, 比较2个元素的cdr, 如果等于忽略第一个元素, 如果不相等,则尝试将第一个元素与列表中的下一个未检查元素进行比较。

澄清一些例子:

((111)(211)(3 1 1)) - > ((3 1 1))

((2 2 0)(4 1 1)(1 2 0)(3 0 1)(8 1 1)) - > ((1 2 0)(3 0 1)(8 1 1))

(defun simplify2 (vari)
    ;If last term: stop
    (if (equal (cdr vari) nil) vari

        ;If cdr of first and second term are equal...
        (if (equal (cdar vari) (cdr (cadr vari)))

            ;Ignore the first term and continue with the rest of the list
            (simplify2 (cdr vari))

            ;Otherwise (this is the line which isn't working)
            (cons (car vari) (simplify2 (cdr vari))))))

目前代码只有当所有“喜欢”的术语在列表中彼此相邻时才能正常工作。

1 个答案:

答案 0 :(得分:7)

使用删除重复项的评论中的

Le Petit Prince's suggestion可能就是您想要的。 删除重复是非破坏性的(参见 delete-duplicates ,这可能是破坏性的),并且它被指定为返回一个新列表,其中除了最后一个实例之外的所有实例省略了一个元素(强调添加):

  

remove-duplicates

     

remove-duplicates 会返回修改后的序列副本   与序列中出现的另一个元素匹配的元素   除去。 ...序列的元素成对比较,和   如果任何两个匹配,则序列中较早出现的那个是   丢弃,除非结尾是真的,在这种情况下是后来的   序列被丢弃。

您需要指定一个参数,以指示实际应该比较的是元素的 cdr ,以及测试参数表明它们应与相等进行比较。因此:

(remove-duplicates '((1 1 1) (2 1 1) (3 1 1))
                   :test 'equal 
                   :key 'cdr)
;=> ((3 1 1))

(remove-duplicates '((2 2 0) (4 1 1) (1 2 0) (3 0 1) (8 1 1))
                   :test 'equal
                   :key 'cdr)
;=> ((1 2 0) (3 0 1) (8 1 1))