Replace an item in a list in Common Lisp?

前端 未结 10 1717
春和景丽
春和景丽 2021-02-02 10:12

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

相关标签:
10条回答
  • 2021-02-02 10:25
    (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.

    0 讨论(0)
  • 2021-02-02 10:26
    (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 讨论(0)
  • 2021-02-02 10:28

    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

    0 讨论(0)
  • 2021-02-02 10:32

    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

    0 讨论(0)
  • 2021-02-02 10:33

    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)))))
    
    0 讨论(0)
  • 2021-02-02 10:33

    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

    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.

    0 讨论(0)
提交回复
热议问题