Iteración de la lista Lisp
Pregunta
Tengo una función que obtiene x(un valor) y xs(una lista) y elimina todos los valores que son mayores que x de la lista.Bueno, no funciona, ¿puedes decirme por qué?
(defun biggerElems(x xs)
(let ((xst))
(dolist (elem xs)
(if (> x elem)
(setf xst (remove elem xs))))
xst))
Solución
Creo que es esta línea la que no está bien:
(setf xst (remove elem xs))))
El primer argumento para setf
es el lugar, seguido del valor.Parece que lo tienes al revés (y xst
es cualquiera nil
o no inicializado).
Puede que le resulte más fácil hacer esto:
(defun biggerElems (x xs)
(remove-if (lambda (item) (> item x)) xs))
Otros consejos
Lo más conciso que yo sepa:
(defun bigger-elements (x xs) (remove x xs :test #'<))
al devolver una lista nueva, elimina todos los elementos y de xs para los cuales
(< y x)
o usando el famoso LOOP:
(defun bigger-elements-2 (x xs)
(loop for e in xs
unless (< e x)
collect e))
Funcionó así:
(defun filterBig (x xs)
(remove-if (lambda (item) (> item x)) xs))
¿Para qué fue el '#'?No se compiló con él.
Si desea hacer esto a la manera Lisp, puede usar la recursividad para devolver la nueva lista:
(defun biggerElems (x xs)
(cond ((null xs) NIL)
((< x (car xs))
(biggerElems x (cdr xs)))
(t
(cons (car xs) (biggerElems x (cdr xs))))))
@Luis Oliveira
Esta solución contrasta con la publicada en la pregunta.Si tuviéramos que hacer algo un poco más complicado, es importante basarnos en el enfoque recursivo para manipular listas.
@Ben:No es la llamada a setf la que está mal; el problema es que no está actualizando xs.
es decir:xst se establece en xs con el elemento eliminado, pero xs no se actualiza.Si se va a eliminar un segundo elemento, xst tendrá el primero nuevamente.
necesitaría vincular xst a xs y reemplazar xs en la llamada de eliminación con xst.Esto eliminaría todos los elementos que x sean mayores que.es decir:
(defun biggerElems(x xs)
(let ((xst xs))
(dolist (elem xs)
(when (> x elem)
(setf xst (remove elem xst))))
xst))
Podría ser un poco más rápido configurar xst en (copiar lista xs) y luego usar eliminar en lugar de eliminar (eliminar es destructivo...Dependiendo de su implementación, puede ser más rápido que eliminar.Dado que llama a esto varias veces, puede obtener un mejor rendimiento copiando la lista una vez y eliminándola de forma destructiva).
Alternativamente:
(defun bigger-elems (x xs) ; I prefer hyphen separated to camelCase... to each his own
(loop for elem in xs when (<= x elem) collect elem))
Volviendo a leer tu publicación original, es un poco confuso...dices que eliminas todos los elementos mayores que x, pero parece que tu código está intentando eliminar todos los elementos que x son mayores.Las soluciones que escribí devuelven todos los elementos mayores que x (es decir:eliminar todos los elementos x es mayor que).
¿Para qué fue el '#'?No se compilaron con eso.
Error de tipografía.Normalmente te refieres a funciones con #'
(como (remove-if #'oddp list)
), pero cuando estaba editando, olvidé eliminar el '#'.