Как мне сохранить результат списка в новом списке?

Я хочу удалить с двумя указанными списками элементы, которых нет в обоих.

Код, который я пытаюсь это:

(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 перед возвращением. (Это безопасно, потому что список был выделен локально процедурным кодом: ничто другое в программе не знает о списке до тех пор, пока не будет возвращено его значение, поэтому деструктивная перестановка не влияет на другие функции или модули).

Другие вопросы по тегам