Заменить элемент в списке в Common Lisp? - PullRequest
23 голосов
/ 05 октября 2008

У меня есть список вещей (я назову это L), индекс (N) и новая вещь (NEW). Если я хочу заменить вещь в L в N на NEW, каков наилучший способ сделать это? Должен ли я получить список до N и от N до конца списка, а затем склеить новый список из первой части, NEW и последней части, используя список? Или есть лучший способ сделать это?

Ответы [ 10 ]

25 голосов
/ 05 октября 2008
(setf (nth N L) NEW)

должен сделать трюк.

8 голосов
/ 05 октября 2008

Как часто вы собираетесь это делать; если вы действительно хотите массив, вы должны использовать array . В противном случае, да, функция, которая создает новый список, состоящий из копии первых N элементов, нового элемента и хвоста, будет в порядке. Я не знаю, какая встроенная функция у меня в голове, но я давно не программировал на Лиспе.

Вот решение в Scheme (потому что я знаю это лучше, чем Common Lisp, и у меня есть переводчик для проверки моей работы):

(define (replace-nth list n elem)
  (cond
    ((null? list) ())
    ((eq? n 0) (cons elem (cdr list)))
    (#t (cons (car list) (replace-nth (cdr list) (- n 1) elem)))))
6 голосов
/ 05 октября 2008
(setf (nth N L) T)

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

4 голосов
/ 05 октября 2008

Я просто пытаюсь исправить код Хаззена:

(define (replace-nth list n elem)
  (cond 
    ((null? list) ())
    ((eq? n 0) (cons elem list))
    (#t (cons(car list) (replace-nth (cdr list) (- n 1) elem)))))

> (replace-nth (list 3 2 9 2) 2 8)
(3 2 8 9 2)

Этот код вставил новый элемент в список. Если мы хотим заменить элемент:

(define (replace-nth list n elem)
  (cond 
    ((null? list) ())
    ((eq? n 0) (cons elem (cdr list)))
    (#t (cons(car list) (replace-nth (cdr list) (- n 1) elem)))))

> (replace-nth (list 3 2 9 2) 2 8)
(3 2 8 2)

0 <= n <= длина (список) - 1 </p>

3 голосов
/ 05 октября 2008

hazzen совет хорош (используйте массивы), так как вы, вероятно, захотите сделать много таких разрушительных обновлений, а списки очень неэффективны при произвольном доступе. Самый простой способ сделать это

(setq A (make-array 5) :initial-contents '(4 3 0 2 1))
(setf (elt 2 A) 'not-a-number)

где A - массив (хотя elt работает для любой последовательности).

Однако, если вы должны быть работоспособным, то есть

  1. Вы хотите сохранить старый и новый списки
  2. Вы хотите, чтобы старое и новое разделяли как можно больше памяти.

Тогда вам следует использовать Common Lisp-эквивалент кода Хаззена:

(defun replace1 (list n elem)
  (cond
    ((null list) ())
    ((= n 0) (cons elem list))
    (t (cons (car list) (replace1 (cdr list) (1- n) elem)))))

Это выглядит медленно, потому что это так, и, вероятно, поэтому оно не включено в стандарт.

код Хаззена - это версия Scheme, которая полезна, вот что вы используете.

1 голос
/ 09 февраля 2012

быстро вы можете сделать это с помощью JS на list-replace

1 голос
/ 09 октября 2008

Используйте [REPLACE] [1] (я использую X вместо вашего T, так как T - истинное значение в Лиспе):

(replace L (list X) :start1 N)

[1]: http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm ЗАМЕНИТЬ

1 голос
/ 05 октября 2008

Звучит так, будто вы хотите либо rplaca, либо заменить. См http://www.lispworks.com/documentation/HyperSpec/Body/f_rplaca.htm или http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm#replace

0 голосов
/ 08 февраля 2011
(defun replace-nth-from-list  (list n elem)  
      (cond  
        ((null list) ())  
        (t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))
0 голосов
/ 05 октября 2008

Очевидное решение медленное и использует память, как отмечали другие. Если возможно, вы должны попытаться отложить замену элемента (ов) до тех пор, пока вам не потребуется выполнить еще одну поэлементную операцию в списке, например, (loop for x in list do ...).

Таким образом, вы амортизируете консигнацию (память) и итерацию (процессор).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...