I've been looking for an efficient way of removing consecutive duplicates in a list of points.
My original thinking was to loop through the elements of the list making a comparison with the (n-1)th element and removing it if its equal. But then it is not trivial to remove an element in a list and using another function would make it inefficient.
I am aware of Lee Mac's RemoveOnce function but I don't know how to modify it to make a comparison between consecutive elements of a list.
The goal as an example would be the following:
List = (p1 p2 p3 p3 p3 p2 p2 p4)
List_without_consecutive_duplicates = (p1 p2 p3 p2 p4)
Thanks!
Here's an iterative method:
(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)
)
And here's a recursive method:
(defun remcondupes ( l )
(if l
(if (equal (car l) (cadr l) 1e-8)
(remcondupes (cdr l))
(cons (car l) (remcondupes (cdr l)))
)
)
)
In both of the above, the first element in the list is compared to the second using the equal
function with a tolerance of 1e-8
(since we're comparing points), with the first element discarded if this test is validated.
Testing:
_$ (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))
Alternatively, to account for consecutive points each successively within the comparison tolerance (per Will's comments below), you might consider the following variations:
(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)))
)
)
)