Удаление повторяющихся элементов в списке строк в elisp
Учитывая такой список, как
(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")
как бы я построил новый список с удаляемыми повторяющимися строками, а также nil
stripped, i.e.
(list "foo" "bar" "moo" "affe")
Порядок элементов должен быть сохранен - первое появление строки не может быть удалено.
Списки, с которыми я имею дело, коротки, поэтому нет необходимости использовать что-либо вроде хеш-таблицы для проверки уникальности, хотя это тоже не повредит. Однако использование cl
функциональности не является жизнеспособным вариантом.
Ответы
Ответ 1
Здесь ya go:
(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)))
Ответ 2
Попробуйте "Наборы и списки" в разделе "Списки" Справочное руководство Emacs Lisp:
(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")))
Ответ 3
Общий 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 лет, не считая менее признанных прошлых воплощений.)
Ответ 4
Если вы используете dash.el
, то все, что вам нужно:
(-distinct (-non-nil '(1 1 nil 2 2 nil 3)) ; => (1 2 3)
dash.el
написан Magnar Sveen, и это отличная библиотека манипулирования списками с множеством функций для всех видов задач. Я рекомендую установить его, если вы напишете много кода Elisp. Функция -distinct
удаляет повторяющиеся элементы в списке, -non-nil
удаляет элементы nil
. Хотя приведенного выше кода достаточно, ниже я описываю альтернативный подход, поэтому не стесняйтесь игнорировать остальную часть сообщения.
-non-nil
был добавлен в версии 2.9, поэтому, если по какой-то причине вы должны использовать более ранние версии, другой способ добиться этого - использовать -keep
со встроенной функцией identity
, которая возвращает только то, что дано: (identity 1) ; => 1
. Идея состоит в том, что -keep
хранит только элементы, для которых предикат возвращает true ( "non-nil" в Lisp жаргоне). identity
, очевидно, возвращает non-nil только для любых значений, которые не равны nil:
(-distinct (-keep 'identity '(1 1 nil 2 2 nil 3)) ; => (1 2 3)