Replace an item in a list in Common Lisp?

ⅰ亾dé卋堺 提交于 2019-12-02 22:12:51
l0st3d
(setf (nth N L) NEW)

should do the trick.

hazzen

How often are you going to do this; if you really want an array, you should use an array. Otherwise, yes, a function that makes a new list consisting of a copy of the first N elements, the new element, and the tail will be fine. I don't know of a builtin off the top of my head, but I haven't programmed in Lisp in a while.

Here is a solution in Scheme (because I know that better than Common Lisp, and have an interpreter for checking my work):

(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)))))
(setf (nth N L) T)

is the clearest, most succinct, and fastest way, if what you want to do is a "destructive" modification, i.e. actually change the existing list. It does not allocate any new memory.

I just try to fix hazzen's code:

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

This code inserted new element in the list. If we want to replace an element:

(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 <= length(list) - 1

hazzen's advice is good (use arrays) since you probably want to do a lot of these destructive updates and lists are very inefficient at random access. The easiest way to do this

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

where A is an array (although elt works for any sequence).

However, if you must be functional, that is

  1. You want to keep around both the old and new lists
  2. You want the old and new to share as much memory as possible.

Then you should use the Common Lisp equivalent of hazzen's code:

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

This looks slow because it is, and that's probably why it's not included in the standard.

hazzen's code is the Scheme version, which is useful is that's what you're using.

Use [REPLACE][1] (I use X instead of your T as T is the true value in Lisp):

(replace L (list X) :start1 N)

[1]: http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm REPLACE

quickly you can do it with JS on list-replace

The obvious solution is slow and uses memory, as noted by others. If possible, you should try to defer replacing the element(s) until you need to perform another element-wise operation on the list, e.g. (loop for x in list do ...).

That way, you'll amortize away the consing (memory) and the iteration (cpu).

M L
(defun replace-nth-from-list  (list n elem)  
      (cond  
        ((null list) ())  
        (t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!