Удаление повторяющихся элементов в списке строк в 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)))

Ответ 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)