recursivas - Reemplazar un elemento en una lista en Common Lisp?
recorrer una lista en lisp (10)
Tengo una lista de cosas (la llamaré L), un índice (N) y algo nuevo (NUEVO). Si quiero reemplazar la cosa en L at N con NEW, ¿cuál es la mejor manera de hacerlo? ¿Debo subir la lista secundaria a N y de N al final de la lista y luego unir una nueva lista de la primera parte, NUEVA y la última parte usando la lista? ¿O hay una mejor manera de hacer esto?
¿Con qué frecuencia vas a hacer esto? si realmente quieres una matriz, deberías usar una array . De lo contrario, sí, una función que hace una nueva lista que consiste en una copia de los primeros N elementos, el nuevo elemento y la cola estará bien. No sé de un builtin de la parte superior de mi cabeza, pero no he programado en Lisp por un tiempo.
Aquí hay una solución en Scheme (porque lo sé mejor que Common Lisp, y tengo un intérprete para verificar mi trabajo):
(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)))))
El consejo de hazzen es bueno (usa arreglos) ya que probablemente quieras hacer muchas de estas actualizaciones destructivas y las listas son muy ineficientes al acceder de forma aleatoria. La forma más fácil de hacer esto
(setq A (make-array 5) :initial-contents ''(4 3 0 2 1))
(setf (elt 2 A) ''not-a-number)
donde A es una matriz (aunque elt
funciona para cualquier secuencia).
Sin embargo, si debe ser funcional, eso es
- Desea mantener las listas antiguas y nuevas
- Desea que lo viejo y lo nuevo compartan tanta memoria como sea posible.
Entonces deberías usar el equivalente de Common Lisp al código de Hazzen:
(defun replace1 (list n elem)
(cond
((null list) ())
((= n 0) (cons elem list))
(t (cons (car list) (replace1 (cdr list) (1- n) elem)))))
Esto parece lento porque lo es, y es probable que por eso no esté incluido en el estándar.
El código de hazzen es la versión de Scheme, que es útil. Es lo que estás usando.
La solución obvia es lenta y usa memoria, como lo notaron otros. Si es posible, debe intentar diferir el reemplazo del elemento (s) hasta que necesite realizar otra operación de elemento en la lista, por ejemplo (loop for x in list do ...)
.
De esa forma, amortizará el consumo (memoria) y la iteración (cpu).
Parece que quieres o bien rplaca o bien reemplaza. Consulte http://www.lispworks.com/documentation/HyperSpec/Body/f_rplaca.htm o http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm#replace
Solo intento arreglar el código de Hazzen:
(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)
Este código insertó un nuevo elemento en la lista. Si queremos reemplazar un elemento:
(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 <= longitud (lista) - 1
Utilice [REPLACE] [1] (uso X en lugar de su T ya que T es el valor verdadero en Lisp):
(replace L (list X) :start1 N)
[1]: http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm REEMPLAZAR
rápidamente puede hacerlo con JS en lista-reemplazar
(defun replace-nth-from-list (list n elem)
(cond
((null list) ())
(t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))
(setf (nth N L) NEW)
debería hacer el truco.
(setf (nth N L) T)
es la manera más clara, sucinta y rápida, si lo que quieres hacer es una modificación "destructiva", es decir, cambiar la lista existente. No asigna ninguna memoria nueva.