Как мне сохранить результат списка в новом списке?
Я хочу удалить с двумя указанными списками элементы, которых нет в обоих.
Код, который я пытаюсь это:
(defun remove_odd_ones(L1 L2)
(cond ((or (null L1) (null L2)) nil)
((dolist (x L2) (if (not(member x L1)) (remove x L2))))))
(remove_odd_ones '(a b c c e k) '(a b c p d d n))
Что я ожидаю: (a b c c)
Результат, который я получаю: NIL
Любая идея о том, какую функцию я могу использовать для сохранения dolist
результаты в новом списке?
1 ответ
(remove_odd_ones '(a b c c e k) '(a b c p d d n))
Что я ожидаю: (a b c c)
Это называется "пересечение множества":
Lisp> (intersection '(a b c c e k) '(a b c p d d n))
(A B C C)
Как мы можем (неэффективно) сделать это сами:
(defun our-intersection (l1 l2)
(mapcan (lambda (l1-item)
(if (member l1-item l2)
(list l1-item)))
l1))
Карта над l1
, собирая те элементы, которые находятся в l2
,
dolist
функция не подходит для этого, потому что она не является функциональной / аппликативной; это обязательное зацикленное устройство. Если вы хотите собрать список результатов с dolist
Вы должны сделать это самостоятельно с помощью действий в теле, с помощью дополнительных переменных:
(defun our-intersection (l1 l2)
(let ((out nil))
(dolist (l1-item l1 out)
(when (member l1-item l2)
(push l1-item out)))))
Мы определяем переменную out
который изначально содержит пустой список. наш dolist
идет над l1
, установив переменную l1-item
каждому элементу по очереди. Если l1-item
происходит в l2
, это выдвигается на out
список:
Lisp> (our-intersection '(a b c c e k) '(a b c p d d n))
(C C B A)
dolist
по крайней мере, давайте укажем, через его третий аргумент, выражение, которое будет производить результирующее значение формы: здесь мы поместили ссылку на out
,
Чтобы получить это в (A B C C)
порядок, мы можем заменить эту ссылку nreverse
звоните, вот так:
(dolist (l1-item l1 (nreverse out))
... )
Это общий шаблон процедурного программирования Common Lisp для списков: накапливайте результаты, нажимая на новый локальный список, а затем разрушительно обращайте его с помощью nreverse
перед возвращением. (Это безопасно, потому что список был выделен локально процедурным кодом: ничто другое в программе не знает о списке до тех пор, пока не будет возвращено его значение, поэтому деструктивная перестановка не влияет на другие функции или модули).