I want to iterate over a list, perform an action with the elements and based on some criteria, I want to get rid of the active element. However, when using the function below I end up in an infinite loop.
(defun foo (list action test)
(do ((elt (car list) (car list)))
((null list))
(funcall action elt)
(when (funcall test elt)
(delete elt list))))
(setq list '(1 2 3 4))
(foo list #'pprint #'oddp)
-> infinite loop
Is it not possible as it points to itself? In the end, elt is (car list) of course.
Is this a correct assessment? And how could I solve this efficiently?
Actually you can alter the state of your list while iterating over it. You will just have to use
rplacdin addition todelete, and control the advancement along the list not in the iteration clause, but inside the do body:You should call it via
copy-listif you don’t want it to destroy the argument list.If you want to remove from your list not all elements equal to
eltthat passed the test, but rather all such that will pass the test, then thedeletecall will need to be passed thetestfunction as the:testargument.(edit:) and even much simpler and straightforward, like this (non-destructive) version: