#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))