AutoLISP:删除列表中的连续重复项

AutoLISP: Removing consecutive duplicates in list

我一直在寻找一种有效的方法来删除点列表中的连续重复项。

我最初的想法是遍历列表的元素,与第 (n-1) 个元素进行比较,如果相等则将其删除。但是,删除列表中的元素并不简单,使用另一个函数会使它效率低下。

我知道 Lee Mac 的 RemoveOnce 函数,但我不知道如何修改它以在列表的连续元素之间进行比较。

目标示例如下:

List = (p1 p2 p3 p3 p3 p2 p2 p4)

List_without_consecutive_duplicates = (p1 p2 p3 p2 p4)

谢谢!

这是我认为 AutoLISP 合法的一种方式:

(defun remove-successive-duplicates (l / results current)
  (cond
   ((null l)
    l)
   (t
    (setq current (car l)
          results (list current))
    (foreach e (cdr l)
      (cond
       ((not (eq e current))
        (setq current e
              results (cons e results)))))
    (reverse results))))

如果列表上有破坏性函数但看起来没有,或者列表过滤函数看起来也没有,你可以做得更好。

这是另一种更漂亮但会导致长列表堆栈溢出的方法:

(defun remove-successive-duplicates (l)
  (cond
   ((or (null l) (null (cdr l)))
    l)
   (t
    (cons (car l) (remove-current-duplicates-loop (cdr l) (car l))))))

(defun remove-successive-duplicates-loop (l current)
  (cond
   ((null (cdr l))
    (cond
     ((eq (car l) current)
      '())
     (t
      l)))
   ((eq (car l) current)
    (remove-successive-duplicates-loop (cdr l) current))
   (t
    (cons (car l) (remove-successive-duplicates-loop (cdr l) (car l))))))

这是一个迭代方法:

(defun remcondupes ( l / r )
    (while l
        (if (not (equal (car l) (cadr l) 1e-8))
            (setq r (cons (car l) r))
        )
        (setq l (cdr l))
    )
    (reverse r)
)

这是一个递归方法:

(defun remcondupes ( l )
    (if l
        (if (equal (car l) (cadr l) 1e-8)
            (remcondupes (cdr l))
            (cons (car l) (remcondupes (cdr l)))
        )
    )
)

在上面两个中,列表中的第一个元素与第二个元素使用 equal 函数进行比较,容差为 1e-8(因为我们正在比较点),其中如果此测试通过验证,则丢弃第一个元素。

测试:

_$ (setq p1 '(1.2 2.3) p2 '(3.4 4.5) p3 '(5.6 6.7) p4 '(7.8 8.9))
(7.8 8.9)
_$ (setq lst (list p1 p2 p3 p3 p3 p2 p2 p4))
((1.2 2.3) (3.4 4.5) (5.6 6.7) (5.6 6.7) (5.6 6.7) (3.4 4.5) (3.4 4.5) (7.8 8.9))
_$ (remcondupes lst)
((1.2 2.3) (3.4 4.5) (5.6 6.7) (3.4 4.5) (7.8 8.9))

编辑:

或者,要在比较公差范围内连续计算连续点(根据下面 Will 的评论),您可以考虑以下变体:

(defun remcondupes ( l / r )
    (while l
        (if (equal (car l) (cadr l) 1e-8)
            (setq l (cons (car l) (cddr l)))
            (setq r (cons (car l) r)
                  l (cdr l)
            )
        )
    )
    (reverse r)
)
(defun remcondupes ( l )
    (if l
        (if (equal (car l) (cadr l) 1e-8)
            (remcondupes (cons (car l) (cddr l)))
            (cons (car l) (remcondupes (cdr  l)))
        )
    )
)