Заменить элемент в списке ассоциаций в elisp

У меня есть список в emacs lisp, например:

(setq a1
 '((:k1 . 1)
   (:k2 . 2)
   (:k3 . 3)))

и я хочу изменить значение: k1 на 10, например (:k1 . 10). Как мне это сделать?

Пробовал (setf (assoc :k1 a1) '(:k1 . 10)) - не помогло.


person Mirzhan Irkegulov    schedule 08.04.2012    source источник


Ответы (6)


В списках вы обычно добавляете новый минус перед старым, чтобы «затенить» старое значение, например так:

(add-to-list 'a1 '(:k1 10))

После этого (assoc :k1 a1) вернет 10.

Если вы хотите «отменить» свое изменение, чтобы assoc снова вернуло ваше старое значение, используйте этот код:

(setq a1 (delq (assoc :k1 a1) a1))

Это удалит ПЕРВОЕ соответствие для :k1 из a1.

person krzysz00    schedule 08.04.2012

Начиная с Emacs 25.1, alist-get является формой места, поэтому вы можете:

(setf (alist-get :k1 a1) 10)
person Dale    schedule 26.11.2016

Макрос setf ничего не знает о assoc, но вы все равно можете использовать этот подход чуть более ручным способом:

(let ((item (assoc :k1 a1)))
  (setf (car item) :k1)
  (setf (cdr item) 10))

и если все, что требуется, это установить cdr для данного автомобиля (а не заменить оба), то мы можем упростить это до простого:

(setf (cdr (assoc :k1 a1)) 10)
person phils    schedule 08.04.2012
comment
Вероятно, нет необходимости устанавливать для автомобиля значение :k1, так как это уже значение. Как правило, лучше добавлять новые значения в списки assoc, чем изменять их, но все зависит от того, почему вы пытаетесь установить новое значение. - person Vatine; 08.04.2012
comment
Согласен, но поскольку я адаптировал код в вопросе, и это действительно установило машину, я также включил это сюда. Конечно если установка машины не желательна, то код можно упростить, так что добавлю этот вариант. - person phils; 08.04.2012

Эта более короткая и простая версия у меня работает в Emacs Lisp (MAC Lisp):

(setcdr (assoc :k1 a1) 10)

или, если вы используете Common Lisp:

(rplacd (assoc :k1 a1) 10)

(Обратите внимание, что setcdr и rplacd могут вести себя немного по-разному, когда речь заходит о том, какое значение они возвращают.)

person Liman    schedule 14.04.2018

А как насчет assq-delete-all:

(setq sql-product-alist
      (cons '(ms-tsql :server ....)
            (assq-delete-all 'ms-tsql sql-product-alist)))
person gavenkoa    schedule 10.04.2015

Вот функция, основанная на предложении гавенкоа -

(defun alist-set (alist-symbol key value)
  "Set KEY to VALUE in alist ALIST-SYMBOL."
  (set alist-symbol
        (cons (list key value) 
              (assq-delete-all key (eval alist-symbol)))))

использование -

(let ((foo '((a 1) (b 2))))
  (alist-set 'foo 'a 3)
  foo) ; => ((a 3) (b 2))
person Brian Burns    schedule 11.12.2015