Pergunta
Eu tenho uma função que obtém x(um valor) e xs(uma lista) e remove todos os valores maiores que x da lista.Bem, não funciona, você pode me dizer por quê?
(defun biggerElems(x xs)
(let ((xst))
(dolist (elem xs)
(if (> x elem)
(setf xst (remove elem xs))))
xst))
Solução
Acho que é esta linha que não está certa:
(setf xst (remove elem xs))))
O primeiro argumento a setf
é o local, seguido do valor.Parece que você está ao contrário (e xst
é também nil
ou não inicializado).
Você pode achar mais fácil fazer isso:
(defun biggerElems (x xs)
(remove-if (lambda (item) (> item x)) xs))
Outras dicas
AFAIK mais conciso:
(defun bigger-elements (x xs) (remove x xs :test #'<))
retornando uma nova lista, ele remove todos os elementos y de xs para os quais
(< y x)
ou usando o famoso LOOP:
(defun bigger-elements-2 (x xs)
(loop for e in xs
unless (< e x)
collect e))
Funcionou assim:
(defun filterBig (x xs)
(remove-if (lambda (item) (> item x)) xs))
Para que servia o '#'?Não foi compilado com ele.
Se você quiser fazer isso do jeito Lisp, você pode usar recursão para retornar a nova lista:
(defun biggerElems (x xs)
(cond ((null xs) NIL)
((< x (car xs))
(biggerElems x (cdr xs)))
(t
(cons (car xs) (biggerElems x (cdr xs))))))
@Luís Oliveira
Esta solução deve contrastar com a postada na pergunta.Se precisássemos fazer algo um pouco mais complicado, seria importante nos basearmos na abordagem recursiva para manipular listas.
@Ben:Não é a chamada setf que está errada - o problema é que ele não está atualizando xs.
ou seja:xst está sendo definido como xs com o elemento removido, mas xs não está sendo atualizado.Se um segundo elemento for removido, xst terá o primeiro de volta.
você precisaria vincular xst a xs e substituir xs na chamada remove por xst.Isso removeria todos os elementos que x é maior que.ou seja:
(defun biggerElems(x xs)
(let ((xst xs))
(dolist (elem xs)
(when (> x elem)
(setf xst (remove elem xst))))
xst))
Pode ser um pouco mais rápido definir xst como (lista de cópias xs) e depois usar delete em vez de remover (excluir é destrutivo...dependendo da sua implementação, pode ser mais rápido que remover.Como você está chamando isso várias vezes, poderá obter melhor desempenho copiando a lista uma vez e excluindo-a destrutivamente).
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))
Olhando para trás em sua postagem original, é um pouco confuso ...você diz que remove todos os elementos maiores que x, mas seu código parece estar tentando remover todos os elementos que x é maior.As soluções que escrevi retornam todos os elementos maiores que x (ou seja:remova todos os elementos que x é maior que).
Para que servia o '#'?Não compilou com ele.
Erro de digitação.Normalmente você se refere a funções com #'
(como (remove-if #'oddp list)
), mas quando estava editando, esqueci de remover o '#'.