Как рассчитать разницу между двумя наборами в emacs lisp, наборы должны быть списками

Как рассчитать разницу между двумя наборами в Emacs Lisp? Наборы должны быть списками. Программа должна быть очень простой и короткой, иначе я ее не пойму. Я новичок.

Спасибо

4 ответа

E сть set-difference функция в расширениях Common Lisp:

elisp> (require 'cl)
cl
elisp> (set-difference '(1 2 3) '(2 3 4))
(1)

Когда я пишу код Elisp, который имеет много преобразований данных списка, я использую dash библиотека, потому что она имеет множество функций для работы со списками. Установить разницу можно с помощью -difference:

(-difference '(1 2 3 4) '(3 4 5 6)) ;; => '(1 2)

Отказ от ответственности: это не эффективный способ сделать это в eLisp. Эффективным способом является использование хеш-таблицы с хеш-функцией, но поскольку вы спрашивали о списках, то вот оно:

(defun custom-set-difference (a b)
  (remove-if
     #'(lambda (x) (and (member x a) (member x b)))
     (append a b)))

(custom-set-difference '(1 2 3 4 5) '(2 4 6))

(1 3 5 6)

(defun another-set-difference (a b)
  (if (null a) b
    (let (removed)
      (labels ((find-and-remove
                (c)
                (cond
                 ((null c) nil)
                 ((equal (car c) (car a))
                  (setq removed t) (cdr c))
                 (t (cons (car c) (find-and-remove (cdr c)))))))
        (setf b (find-and-remove b))
        (if removed
            (another-set-difference (cdr a) b)
          (cons (car a) (another-set-difference (cdr a) b)))))))

(another-set-difference '(1 2 3 4 5) '(2 4 6))

(1 3 5 6)

Второй немного более эффективен, потому что он удаляет элементы, поскольку он делает последовательные проверки, но первый короче и более прямолинейен.

Также обратите внимание, что списки не являются хорошим представлением множеств, потому что они, естественно, допускают повторение. Хеш-карты лучше для этой цели.

Вот простое и краткое определение, которое должно быть легко понять. Это по сути так же, как set-difference функция в библиотеке Common Lisp для Emacs, но без какой-либо обработки аргумента TEST.

(defun set-diff (list1 list2 &optional key)
  "Combine LIST1 and LIST2 using a set-difference operation.
Optional arg KEY is a function used to extract the part of each list
item to compare.

The result list contains all items that appear in LIST1 but not LIST2.
This is non-destructive; it makes a copy of the data if necessary, to
avoid corrupting the original LIST1 and LIST2."
  (if (or (null list1)  (null list2))
      list1
    (let ((keyed-list2  (and key  (mapcar key list2)))
          (result       ()))
      (while list1
        (unless (if key
                    (member (funcall key (car list1)) keyed-list2)
                  (member (car list1) list2))
          (setq result  (cons (car list1) result)))
        (setq list1  (cdr list1)))
      result)))

GNU Emacs Lisp Reference Manual, наборы и списки предлагает использовать сл-Lib"s
сл посаженных разности LIST1 list2 &key :test :test-not :key

(require 'cl-lib)
(cl-set-difference '(1 2 3) '(2 3 4))
(1)
Другие вопросы по тегам