Как рассчитать разницу между двумя наборами в 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)