Как добавить несколько элементов в список в Emacs lisp

#list #emacs #elisp

#Список #emacs #elisp

Вопрос:

В Emacs lisp есть add-to-list возможность добавить один элемент в список (если он еще не существует).

Вместо одного я хочу добавить несколько элементов. Кроме того, я не хочу фильтровать повторяющиеся элементы, но, тем не менее, добавляю их в список.

В настоящее время я реализовал следующую функцию:

 (defun append-to-list (list-var elements)
  "Append ELEMENTS to the end of LIST-VAR.

The return value is the new value of LIST-VAR."
  (set list-var (append (symbol-value list-var) elements)))
  

Функция делает то, что я хочу, но мне было интересно, существует ли что-то подобное (или лучше) в Emacs lisp. Я не хочу изобретать велосипед.

Обновление 1: Стефан указывает ниже, что этот код не работает с лексической областью видимости. Есть ли способ заставить это работать?

Обновление 2: Раньше я думал, что фильтрация дубликатов будет хорошей, но это не так. Мне действительно нужны дубликаты.

Комментарии:

1. Ваш код в порядке. Подобной системной функции не существует.

2. Я бы не назвал это «нормально», но да, это сработает. Использование symbol-value и set означает, что его нельзя использовать с переменной с лексической областью действия. Если вам это действительно не нужно, лучше добавить elements в начале, так elements как почти всегда будет короче (а иногда и намного короче), чем list-var .

3. Есть ли способ заставить код работать с лексической областью видимости?

Ответ №1:

Это было бы почти эквивалентно 1, но быстрее, так как он не создает копию исходного списка перед добавлением новых элементов.

 (defun append-to-list (list-var elements)
  "Append ELEMENTS to the end of LIST-VAR.

The return value is the new value of LIST-VAR."
  (unless (consp elements)
    (error "ELEMENTS must be a list"))
  (let ((list (symbol-value list-var)))
    (if list
        (setcdr (last list) elements)
      (set list-var elements)))
  (symbol-value list-var))
  

1 append не копирует последний элемент, а использует его непосредственно в качестве хвоста нового списка, так что эта часть идентична. Однако, если есть дополнительные ссылки на исходный объект списка (или какую-то его часть), тогда будет функциональная разница между копированием этого списка (через append ) и просто его расширением (с setcdr помощью ). Какой из этих двух результатов вы на самом деле хотите, зависит от вас, конечно.

Комментарии:

1. Отрыжка, если исходный список равен нулю!

2. Ох. Исправлено. Спасибо Стефану.

3. По крайней мере, в моем текущем варианте использования я не храню ссылки. Для меня это выглядит более чистым, потому что позволяет избежать копирования. Спасибо! Но можно ли заставить его работать с лексической областью видимости?

4. Нет, вы не можете сделать это с помощью лексической области видимости, когда list-var аргумент является символом , потому что вы уже потеряли доступ к лексическому значению, сделав это. Вам нужно будет передать значение списка и управлять им напрямую.

Ответ №2:

В моем файле инициализации есть следующее, что позволяет добавлять несколько элементов. Я не знаю, насколько эффективно перебирать добавляемые элементы, но это предотвращает дублирование элементов.

 (defun jlp/add-to-list-multiple (list to-add)
  "Adds multiple items to LIST.
Allows for adding a sequence of items to the same list, rather
than having to call `add-to-list' multiple times."
  (interactive)
  (dolist (item to-add)
    (add-to-list list item)))
  

Комментарии:

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

2. Если вам нужны дубликаты, вы можете использовать push вместо add-to-list .

Ответ №3:

Если вас не волнует порядок:

 (setf var (cl-list* elt1 elt2 elt3 var))
  

Последний аргумент to list* становится концом результирующего списка.

Ответ №4:

Вы также можете использовать dash.el, если хотите отфильтровать повторяющиеся элементы.

 (setq list1 (-union list1 list2))
  

Ответ №5:

Иногда я делаю это:

 (setq l `(,@l i1 i2 i3))