Удаление дублирующихся элементов в списке строк в elisp
Учитывая список, такой как
(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
как мне создать новый список с удаленными дублирующимися строками, а также nil
S раздели, т.е.
(list "foo" "bar" "moo" "affe")
Порядок элементов должен быть сохранен - первое вхождение строки не может быть удалено.
Списки, с которыми я здесь работаю, короткие, поэтому нет необходимости использовать что-либо вроде хеш-таблицы для проверки уникальности, хотя это, безусловно, не повредит. Однако, используя cl
функциональность не является жизнеспособным вариантом.
5 ответов
Вот, пожалуйста.
(defun strip-duplicates (list)
(let ((new-list nil))
(while list
(when (and (car list) (not (member (car list) new-list)))
(setq new-list (cons (car list) new-list)))
(setq list (cdr list)))
(nreverse new-list)))
Попробуйте "Наборы и списки" в разделе "Списки" Справочного руководства по Emacs Lisp:
(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")))
Пакет Common Lisp содержит много функций управления списками, в частности remove-duplicates
,
(require 'cl)
(remove-duplicates (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
:test (lambda (x y) (or (null y) (equal x y)))
:from-end t)
Да, я понимаю, ты сказал, что не хочешь использовать cl
, Но я все еще упоминаю это как правильный способ сделать это для других людей, которые могут прочитать эту ветку.
(Почему cl
в любом случае не подходит для вас? Он поставляется с Emacs уже около 20 лет, не считая менее показанных прошлых воплощений.)
Если вы используете dash.el
библиотека, это все, что вам нужно:
(-distinct (-non-nil '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
dash.el
написана Магнаром Свином, и это отличная библиотека для манипулирования списками с множеством функций для самых разных задач. Я рекомендую установить его, если вы пишете много кода Elisp. функция -distinct
удаляет дубликаты элементов в списке, -non-nil
удаляет nil
элементы. Хотя приведенного выше кода достаточно, ниже я опишу альтернативный подход, поэтому не стесняйтесь игнорировать остальную часть поста.
-non-nil
был добавлен в версии 2.9, поэтому, если по какой-то причине вам придется использовать более ранние версии, другой способ добиться того же - использовать -keep
со встроенным identity
функция, которая просто возвращает то, что ей дано: (identity 1) ; => 1
, Идея в том, что -keep
содержит только элементы, для которых предикат возвращает true ("не ноль" на жаргоне Lisp). identity
очевидно, возвращает ненулевое значение только для тех значений, которые не равны нулю:
(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
Это краткий пример:
(delete-duplicates '("~/.emacs.d" "~/.emacs.d") :test #'string-equal) ;; '("~/emacs.d")
В основном вы используете
:test
ключевое слово для выбора функции
string-equal
чтобы проверить, дублируются ли элементы.
В противном случае проверка функции по умолчанию не проверяет равенство строк.