0

Someone tell me what is wrong with this code. I thought I mastered a few scheme skills to solve a friend's problem but it ended up messing my head. I am trying to remove all similar elements off the list. Earlier it was removing only the first element I want to remove, but now its removing the car and the first element f what I want to remove. I am looking for an output like: (delete 3 (list 2 3 4 3 5 3)), returns (2 4 5).

(define (delete n lst)
    (cond 
         ((null? lst) null)
         ((equal? n (car lst)) (cdr lst))
         (else
             (remove n (cdr lst)))))
Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
Adeq Hero
  • 137
  • 1
  • 3
  • 11

2 Answers2

4

It's because of this conditional:

((equal? n (car lst)) (cdr lst))

What this line does is it checks that n is the same as the first element in the list. If it is, it returns the rest of the list. Since your target element is the second element of the list, it returns the rest of the list, from the third element onward. Your first element in the list is completely dropped. You're not keeping track of the OK elements you've checked so far.

From your code, it looks like you want to loop through the elements of the list and, if you find your target value, call remove. If you want to implement it in this fashion, you need to also track the values that you've checked and verified that are not your target value. So your function needs to take three parameters: n, your target; lst the remaining numbers to check; and clean (or whatever you want to call it) that holds the already checked numbers.

This is a working version of your algorithm:

(define (delete n lst clean)
  (cond
    ((empty? lst) clean)
    ((equal? n (car lst)) (delete n (cdr lst) clean))
    (else
      (delete n (cdr lst) (append clean (list (car lst)))))))

You'd call it like so: (delete 3 (list 2 3 4 3 5 3) '())

First it checks if you have numbers left to check. If you don't, it returns your clean list.

Then it checks to see if the first element matches your target element. If it does, then it calls delete again, effectively dropping the first element in the lst (notice it does not append it to the list of clean numbers).

The else, which is reached if the first element is not the target number, appends the first value of lst to the end of clean and calls delete again.

(Note that this code uses tail recursion, which is a way of writing recursive methods that track the intermediate values with each recursive call, as opposed to "regular" recursion that does the calculation at the end. Samrat's answer, below, is a regular recursive solution. A discussion of the tail recursion can be found here.)

From your post, it sounds like you want to remove all instances of the target number. Instead of using the remove function -- which only removes the first instance of the target number -- you should look at using the remove* function, which removes all instances. This would greatly simplify your function. So to remove all instances of 3 from your list, this would suffice:

(remove* '(3) (list 2 3 4 3 5 3))

If you wanted to wrap it in a function:

(define (delete n lst)
  (remove* (list n) lst))

You should read up on map functions in general, since they pretty much do what you're looking for. (They apply a procedure against all elements in a list; The above could also be implemented with a filter-map if you had a more complicated procedure.)

Community
  • 1
  • 1
Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
0

Here's what I came up with:

(define (delete n lst)
  (cond ((empty? lst) lst)
        ((= (car lst) n) (delete n (cdr lst)))
        (else (append (list (car lst)) (delete n (cdr lst))))))