Удаление дублирующихся элементов в списке строк в elisp - PullRequest
19 голосов
/ 28 сентября 2010

Учитывая список, такой как

(list "foo" "bar" nil "moo" "bar" "moo" nil "affe")

, как мне создать новый список с удаленными дублирующимися строками, а также с nil s, то есть

(list "foo" "bar" "moo" "affe")

Порядок элементов должен быть сохранен - ​​первое вхождение строки не может быть удалено.

Списки, с которыми я здесь работаю, короткие, поэтому нет необходимости использовать что-либо вроде хэш-таблицы дляпроверка уникальности, хотя, конечно, это тоже не повредит.Однако использование функциональности cl нецелесообразно.

Ответы [ 4 ]

35 голосов
/ 29 сентября 2010

Попробуйте "Наборы и списки" в разделе "Списки" Справочного руководства по Emacs Lisp :

(delq nil (delete-dups (list "foo" "bar" nil "moo" "bar" "moo" nil "affe")))
16 голосов
/ 29 сентября 2010

Пакет 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 лет, не считая менее значимых прошлых воплощений.)

4 голосов
/ 18 марта 2014

Если вы используете библиотеку 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)
0 голосов
/ 28 сентября 2010

Вот, пожалуйста,

(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)))
...