Список может представлять неупорядоченное математическое множество — достаточно считать значение элементом множества, если оно присутствует в списке, и игнорировать порядок элементов в списке. Для объединения двух множеств используйте append (если вас не беспокоят повторяющиеся элементы). Удалить дубликаты по equal можно с помощью delete-dups или seq-uniq. Другие полезные функции для множеств: memq и delq, а также их версии с equal — member и delete.
Примечание для Common Lisp: В Common Lisp есть функции
union(которая избегает дубликатов) иintersectionдля операций над множествами. В Emacs Lisp варианты этих средств предоставляются библиотекой cl-lib. См. Списки как множества в Расширениях Common Lisp.
Эта функция проверяет, является ли объект элементом списка. Если является, memq возвращает список, начинающийся с первого вхождения объекта. В противном случае возвращает nil. Буква «q» в memq означает, что для сравнения объекта с элементами списка используется eq. Например:
(memq 'b '(a b c b a))
⇒ (b c b a)
(memq '(2) '((1) (2))) ; Два(2)не обязаны бытьeq. ⇒ Не определено; может бытьnilили((2)).
Эта функция деструктивно удаляет все элементы, eq равные объекту, из списка и возвращает результирующий список. Буква «q» в delq означает, что для сравнения объекта с элементами списка используется eq, как в memq и remq.
Обычно при вызове delq следует использовать возвращаемое значение, присваивая его переменной, в которой хранился исходный список. Причина этого объясняется ниже.
Функция delq удаляет элементы из начала списка, просто продвигаясь по списку и возвращая подсписок, который начинается после этих элементов. Например:
(delq 'a '(a b c)) ≡ (cdr '(a b c))
Когда удаляемый элемент находится в середине списка, его удаление включает изменение CDR (см. Изменение CDR списка).
(setq sample-list (list 'a 'b 'c '(4)))
⇒ (a b c (4))
(delq 'a sample-list)
⇒ (b c (4))
sample-list
⇒ (a b c (4))
(delq 'c sample-list)
⇒ (a b (4))
sample-list
⇒ (a b (4))
Обратите внимание, что (delq 'c sample-list) изменяет sample-list, вырезая третий элемент, но (delq 'a sample-list) ничего не вырезает — он просто возвращает более короткий список. Не предполагайте, что переменная, которая ранее содержала аргумент список, теперь содержит меньше элементов или всё ещё содержит исходный список! Вместо этого сохраняйте результат delq и используйте его. Чаще всего мы сохраняем результат обратно в переменную, содержащую исходный список:
(setq flowers (delq 'rose flowers))
В следующем примере (list 4), который delq пытается сопоставить, и (4) в sample-list являются equal, но не eq:
(delq (list 4) sample-list)
⇒ (a c (4))
Если вы хотите удалить элементы, equal равные заданному значению, используйте delete (см. ниже).
Эта функция возвращает копию списка, из которой удалены все элементы, eq равные объекту. Буква «q» в remq означает, что для сравнения объекта с элементами списка используется eq.
(setq sample-list (list 'a 'b 'c 'a 'b 'c))
⇒ (a b c a b c)
(remq 'a sample-list)
⇒ (b c b c)
sample-list
⇒ (a b c a b c)
Функция memql проверяет, является ли объект элементом списка, сравнивая элементы с объектом с помощью eql, поэтому элементы с плавающей запятой сравниваются по значению. Если объект является элементом, memql возвращает список, начинающийся с его первого вхождения в список. В противном случае возвращает nil.
Сравните это с memq:
(memql 1.2 '(1.1 1.2 1.3)) ; 1.2 и 1.2 являются eql.
⇒ (1.2 1.3)
(memq 1.2 '(1.1 1.2 1.3)) ; Два1.2не обязаны бытьeq. ⇒ Не определено; может бытьnilили(1.2 1.3).
Следующие три функции подобны memq, delq и remq, но используют equal вместо eq для сравнения элементов. См. Предикаты равенства.
Функция member проверяет, является ли объект элементом списка, сравнивая элементы с объектом с помощью equal. Если объект является элементом, member возвращает список, начинающийся с его первого вхождения в список. В противном случае возвращает nil.
Сравните это с memq:
(member '(2) '((1) (2))) ; (2) и (2) являются equal.
⇒ ((2))
(memq '(2) '((1) (2))) ; Два(2)не обязаны бытьeq. ⇒ Не определено; может бытьnilили(2).
;; Две строки с одинаковым содержимым являются equal.
(member "foo" '("foo" "bar"))
⇒ ("foo" "bar")
Эта функция удаляет все элементы, equal равные объекту, из последовательности и возвращает результирующую последовательность.
Если последовательность — это список, delete относится к delq так же, как member к memq: он использует equal для сравнения элементов с объектом, как member; когда он находит совпадающий элемент, он вырезает его так же, как это сделал бы delq. Как и в случае с delq, обычно следует использовать возвращаемое значение, присваивая его переменной, в которой хранился исходный список.
Если последовательность — это вектор или строка, delete возвращает копию последовательности с удалёнными всеми элементами, equal равными объекту.
Например:
(setq l (list '(2) '(1) '(2)))
(delete '(2) l)
⇒ ((1))
l
⇒ ((2) (1))
;; Если вы хотите надёжно изменить l,
;; напишите (setq l (delete '(2) l)).
(setq l (list '(2) '(1) '(2)))
(delete '(1) l)
⇒ ((2) (2))
l
⇒ ((2) (2))
;; В этом случае не имеет значения, устанавливаете ли вы l,
;; но вы должны делать это ради другого случая.
(delete '(2) [(2) (1) (2)])
⇒ [(1)]
Эта функция является недеструктивным аналогом delete. Она возвращает копию последовательности (списка, вектора или строки) с удалёнными элементами, equal равными объекту. Например:
(remove '(2) '((2) (1) (2)))
⇒ ((1))
(remove '(2) [(2) (1) (2)])
⇒ [(1)]
Примечание для Common Lisp: Функции
member,deleteиremoveв GNU Emacs Lisp происходят из Maclisp, а не из Common Lisp. Версии в Common Lisp не используютequalдля сравнения элементов.
Эта функция подобна member, за исключением того, что объект должен быть строкой, и она игнорирует различия в регистре букв и текстовом представлении: прописные и строчные буквы считаются равными, а однобайтовые строки преобразуются в многобайтовые перед сравнением.
Эта функция деструктивно удаляет все дубликаты (по equal) из списка, сохраняет результат в списке и возвращает его. Из нескольких equal-вхождений элемента в список delete-dups оставляет первое. См. seq-uniq для недеструктивной операции (см. Последовательности).
Смотрите также функцию add-to-list в Изменение переменных-списков — способ добавления элемента к списку, хранящемуся в переменной и используемому как множество.