问题
I have a list of things (I'll call it L), an index(N) and a new thing(NEW). If I want to replace the thing in L at N with NEW, what is the best way to do this? Should I get the sublist up to N and from N to the end of the list and then glue together a new list from the first part, NEW, and the last part using list? Or is there a better way to do this?
回答1:
(setf (nth N L) NEW)
should do the trick.
回答2:
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)))))
回答3:
(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.
回答4:
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
回答5:
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).
- The elt definition, with examples of setf.
- The make-array definition, with examples
However, if you must be functional, that is
- You want to keep around both the old and new lists
- 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.
回答6:
Sounds like you want either rplaca or replace. See http://www.lispworks.com/documentation/HyperSpec/Body/f_rplaca.htm or http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm#replace
回答7:
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
回答8:
quickly you can do it with JS on list-replace
回答9:
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).
回答10:
(defun replace-nth-from-list (list n elem)
(cond
((null list) ())
(t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))
来源:https://stackoverflow.com/questions/170931/replace-an-item-in-a-list-in-common-lisp