从Common Lisp中的列表中按值删除重复项

时间:2018-12-16 22:18:40

标签: lisp common-lisp

给出两个由多个“对象”组成的列表,格式如下:(name id)如何从第一个列表中获取与第二个名称不匹配的对象?

预期输出:

(remove-duplicates-by-name
  '((Oliver 1) (Charlie 2) (Oscar 20))
  '((Oliver 2)(Charlie 3)))

((Oscar 20))

(remove-duplicates-by-name 
  '((Oliver 1)) 
  '((Oliver 2)(Charlie 3)))

()

(remove-duplicates-by-name 
  '() 
  '((Oliver 2)(Charlie 3)))

()

修改:

输出顺序很重要。示例:

(remove-duplicates-by-name 
  '((Oliver 1) (Charlie 2) (Oscar 20) (Daniel 30)) 
  '((Oliver 2)(Charlie 3)))

正确的输出:((Oscar 20)(Daniel 30))

错误的输出:((Daniel 30)(Oscar 20))

2 个答案:

答案 0 :(得分:3)

这是两个hacky解决方案。

(defun remove-duplicates-by-name (l to-remove)
  ;; low performance with large to-remove lists but fine with short
  ;; ones
  (loop for e in l
        unless (assoc (car e) to-remove)
        collect e))

(defun remove-duplicates-by-name (l to-remove)
  ;; high performance with large to-remove lists but consy and
  ;; probably slow with short ones
  (loop with dups = (loop with dt = (make-hash-table)
                          for e in to-remove
                          do (setf (gethash (car e) dt) t)
                          finally (return dt))
        for e in l
        unless (gethash (car e) dups)
        collect e))

答案 1 :(得分:0)

您的示例与重复项无关,但所有相关事项 与Lists as Sets

例如:

(set-difference '((Oliver 1) (Charlie 2) (Oscar 20)) '((Oliver 2)(Charlie 3)) :key #'car)
==> ((Oscar 20))

(set-difference '((Oliver 1)) '((Oliver 2)(Charlie 3)) :key #'car)
==> ()

(set-difference '() '((Oliver 2)(Charlie 3)) :key #'car)
==> ()