How to calculate the difference between two sets in emacs lisp, sets should be lists

How to calculate the difference between two sets in Emacs Lisp? Sets should be lists. The program should be very simple and short, otherwise I will not understand it. I'm new at this.

thanks

+4
source share
4 answers

There is a set-difference function in common Lisp extensions:

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

Disclaimer: This is not an efficient way to do this in eLisp. The effective way is through a hash table with a hash function, but since you asked about lists, here is this:

 (defun custom-set-difference (ab) (remove-if #'(lambda (x) (and (member xa) (member xb))) (append ab))) (custom-set-difference '(1 2 3 4 5) '(2 4 6)) (1 3 5 6) (defun another-set-difference (ab) (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) 

The second is a bit more efficient because it will remove the elements as it does subsequent checks, but the first is shorter and more straightforward.

Also note that lists are not a good representation of sets, because they naturally allow you to repeat. For this purpose, it is better to use hash maps.

+2
source

Here is a simple and short definition that should be clear. This is essentially the same as the set-difference function in the Lisp shared library for Emacs, but without any processing of the TEST argument.

 (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))) 
+2
source

When I write Elisp code with a lot of transformations of list data, I use dash because it has many functions for working with lists. You can set the difference using -difference :

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

Source: https://habr.com/ru/post/1416683/


All Articles