Skip to main content

set-exclusive-or, nset-exclusive-or

set-exclusive-or, nset-exclusive-or Function

Syntax:

set-exclusive-or list-1 list-2 &key key test test-not → result-list

nset-exclusive-or list-1 list-2 &key key test test-not → result-list

Arguments and Values:

list-1—a proper list.

list-2—a proper list.

test—a designator for a function of two arguments that returns a generalized boolean. test-not—a designator for a function of two arguments that returns a generalized boolean. key—a designator for a function of one argument, or nil.

result-list—a list.

Description:

set-exclusive-or returns a list of elements that appear in exactly one of list-1 and list-2. nset-exclusive-or is the destructive version of set-exclusive-or.

For all possible ordered pairs consisting of one element from list-1 and one element from list-2, the :test or :test-not function is used to determine whether they satisfy the test.

If :key is supplied, it is used to extract the part to be tested from the list-1 or list-2 element. The first argument to the :test or :test-not function is the part of an element of list-1 extracted by the :key function (if supplied); the second argument is the part of an element of list-2 extracted by the :key function (if supplied). If :key is not supplied or nil, the list-1 or list-2 element is used.

The result contains precisely those elements of list-1 and list-2 that appear in no matching pair. The result list of set-exclusive-or might share storage with one of list-1 or list-2.

Examples:

(setq lst1 (list 1 "a" "b") 
lst2 (list 1 "A" "b"))(1 "A" "b")
(set-exclusive-or lst1 lst2)("b" "A" "b" "a")
(set-exclusive-or lst1 lst2 :test #’equal)("A" "a")
(set-exclusive-or lst1 lst2 :test ’equalp) → NIL
(nset-exclusive-or lst1 lst2)("a" "b" "A" "b")
(setq lst1 (list (("a" . "b") ("c" . "d") ("e" . "f"))))
(("a" . "b") ("c" . "d") ("e" . "f"))
(setq lst2 (list (("c" . "a") ("e" . "b") ("d" . "a"))))
(("c" . "a") ("e" . "b") ("d" . "a"))
(nset-exclusive-or lst1 lst2 :test #’string= :key #’cdr)
(("c" . "d") ("e" . "f") ("c" . "a") ("d" . "a"))
lst1 → (("a" . "b") ("c" . "d") ("e" . "f"))
lst2 → (("c" . "a") ("d" . "a"))

Side Effects:

nset-exclusive-or is permitted to modify any part, car or cdr , of the list structure of list-1 or list-2.

Exceptional Situations:

Should be prepared to signal an error of type type-error if list-1 and list-2 are not proper lists.

See Also:

Section 3.2.1 (Compiler Terminology), Section 3.6 (Traversal Rules and Side Effects)

Notes:

The :test-not parameter is deprecated.

Since the nset-exclusive-or side effect is not required, it should not be used in for-effect-only positions in portable code.

Expanded Reference: set-exclusive-or, nset-exclusive-or

Basic symmetric difference

set-exclusive-or returns elements that appear in exactly one of the two lists (but not both).

(set-exclusive-or '(1 2 3 4) '(3 4 5 6))
=> (6 5 2 1)

(set-exclusive-or '(a b c) '(a b c))
=> NIL

Symmetric operation

Unlike set-difference, the result includes unmatched elements from both lists.

(set-exclusive-or '(1 2 3) '(2 3 4 5))
=> (5 4 1)

Using :test for value comparison

(set-exclusive-or '("apple" "banana") '("banana" "cherry") :test #'equal)
=> ("cherry" "apple")

(set-exclusive-or '("Hello") '("hello") :test #'equalp)
=> NIL

Using :key to compare by a component

(set-exclusive-or '((a . 1) (b . 2) (c . 3))
'((b . 9) (c . 8) (d . 4))
:key #'car)
=> ((D . 4) (A . 1))

nset-exclusive-or is destructive

nset-exclusive-or may modify either or both input lists. Always use the return value.

(let ((a (list 1 2 3))
(b (list 2 3 4)))
(nset-exclusive-or a b))
=> (1 4)

Practical example: detecting changes

(let ((old-features '(:logging :auth :cache))
(new-features '(:auth :cache :metrics)))
(set-exclusive-or old-features new-features))
=> (:METRICS :LOGGING)