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)))
)
)
)
我一直在寻找一种有效的方法来删除点列表中的连续重复项。
我最初的想法是遍历列表的元素,与第 (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)))
)
)
)