2008-09-05 10 views
4

Ich habe eine Funktion, die x (ein Wert) und xs (eine Liste) erhält und alle Werte, die größer als x sind, aus der Liste entfernt. Nun, es funktioniert nicht, kannst du mir sagen warum?Lisp Listeniteration

(defun biggerElems(x xs) 
    (let ((xst)) 
    (dolist (elem xs) 
     (if (> x elem) 
      (setf xst (remove elem xs)))) 
    xst)) 

Antwort

5

Ich denke, es ist diese Linie ist, die nicht richtig ist:

(setf xst (remove elem xs)))) 

Das erste Argument für setf der Ort ist, von dem Wert. Es scheint, dass Sie es rückwärts haben (und xst ist entweder nil oder nicht initialisiert).

Sie finden es einfacher, dies zu tun:

(defun biggerElems (x xs) 
    (remove-if (lambda (item) (> item x)) xs)) 
1

Es ist wie es funktioniert:

(defun filterBig (x xs) 
    (remove-if (lambda (item) (> item x)) xs)) 

Was war der '#' für? Es hat sich nicht damit kompiliert.

0

Für was war die '#'? Es hat nicht damit kompiliert.

Typo. Normalerweise beziehen Sie sich auf Funktionen mit (wie (remove-if #'oddp list)), aber als ich redigierte, habe ich vergessen, die '#' zu entfernen.

1

Wenn Sie diese den Lisp Weg machen wollen, könnten Sie Rekursion zurück, um die neue Liste verwenden:

(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

Diese Lösung ist mit dem in der Frage gestellt, um den Kontrast . Hätten wir etwas etwas Komplizierteres tun müssen, ist es wichtig, sich auf den rekursiven Ansatz zur Manipulation von Listen zu stützen.

+0

Nur weil Sie Rekursion in Lisp verwenden können, bedeutet das nicht, dass es der "Lisp Way" ist. Es gibt mehrere Mechanismen, um dies in Lisp zu tun (wie an anderer Stelle hier zu sehen), und alle von ihnen sind idiomatisch. Die rekursive Methode ist einfach die einfachste. –

4

knappste AFAIK:

(defun bigger-elements (x xs) (remove x xs :test #'<)) 

eine neue Liste der Rückkehr, entfernt es alle Elemente y von xs für die

(< y x) 

oder mit dem berühmten LOOP:

(defun bigger-elements-2 (x xs) 
    (loop for e in xs 
     unless (< e x) 
     collect e)) 
1

@ Ben: Es ist nicht der Setf-Aufruf, der falsch ist - das Problem ist, dass er xs nicht aktualisiert.

Dh: xst wird auf xs gesetzt, wenn das Element entfernt ist, aber xs wird nicht aktualisiert. Wenn ein zweites Element entfernt werden soll, hat xst das erste zurück.

müssten Sie xst an xs binden und ersetzen Sie die xs im Aufruf entfernen mit xst. Dies würde dann alle Elemente entfernen, die größer als x sind. dh:

(defun biggerElems(x xs) 
    (let ((xst xs)) 
    (dolist (elem xs) 
     (when (> x elem) 
     (setf xst (remove elem xst)))) 
    xst)) 

Es könnte etwas schneller sein zu setzen xst zu (copy-Liste xs) und dann statt entfernen verwenden löschen (löschen destruktiv ist ... je nach Implementierung kann es schneller sein als entfernen. Da Sie dies mehrmals aufrufen, erhalten Sie möglicherweise eine bessere Leistung, indem Sie die Liste einmal kopieren und löschen.

Alternativ:

(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)) 

zurück über Ihre ursprüngliche Post Sehen, es ist ein wenig verwirrend ist ... Sie sagen, Sie alle Elemente entfernen größer als x, aber Ihr Code sieht aus wie es alle Elemente zu entfernen versucht, x ist größer als. Die Lösungen, die ich geschrieben habe, geben alle Elemente zurück, die größer als x sind (dh: entferne alle Elemente, die größer als x sind).