简体   繁体   中英

eliminate the last occurrence of an element in a list in racket

I just wanted to know, can i create a function in racket which can eliminate the last occurrence of an element in a list, for example,

>(last-without   '(a b  a  (c e) d)    'e)  =  (a b a (c) d)
>(last-without   '(p q  p (r p) q e p r)   'p) = (p q  p (r p) q e r)

Also can this be done by defining a membership testing for nested lists by generalizing built-in member that can be used to set up last-without recursive calls, without using redundant reverses.

(define (last-without list el)
  (define (remove-last-rec lst)
    (cond ((null? lst) '())
          ((equal? (car lst) el) (cdr lst))
          ; Corner case below, if car is a list, we also have to check it for occurences of el
          ((list? (car lst)) (let* ((nested (car lst))
                                    (rest (cdr lst))
                                    (nested-res (last-without nested el)))
                               (if (equal? nested nested-res)
                                   (cons nested-res (remove-last-rec rest)); el did not occur in nested list
                                   (cons nested-res rest)))) ; We did removed it, not remove it from cdr anymore, instead just cons the unchanged cdr.
          (else (cons (car lst) (remove-last-rec (cdr lst))))))

  (reverse ; Reverse filtered list back to original order
   (remove-last-rec 
    (reverse list))))

You'll notice the corner case where (car lst) is a list. If it is a list, we have to check it for occurences of el .

Important is that we call last-without on that list instead of remove-last-rec . This is because nested lists were not reversed by the original reverse in the start call, (reverse (remove-last-rec (reverse list))) .

If you would call remove-last-rec the order of the nested lists will be wrong in the result. I suggest you to try it by yourself (with a wrong call to remove-last-rec ), it is very instructive to try coming up with lists for which you think it might fail.

If you could not find any, try this one. It won't output what you would expect.

(last-without '(a (b c a c) b) 'c)

EDIT : The corner case needs an explicit test to check if (last-without nested el) returns the same nested list or not. If not, the last occurence of el in the nested list nested was filtered out and we don't need to filter out the last occurence of el in rest anymore.

Here is a solution:

(define (last-without lst el)
  (define (aux lst)  ; returns two values: removed and result
    (if (null? lst)
        (values #f '())
        (let-values (((removed result) (aux (cdr lst))))
                (if removed
                    (values removed (cons (car lst) result))
                    (cond ((equal? (car lst) el) (values #t result))
                          ((list? (car lst))
                           (let-values (((removed-from-car result-of-car) (aux (car lst))))
                             (values removed-from-car (cons result-of-car result))))
                          (else (values #f (cons (car lst) result))))))))
  (let-values (((removed result) (aux lst)))
    result))

The auxiliary function performs the removal of the element and returns two values: a boolean which is #t if the element has been removed, and the resulting list. So, after checking that the list is not empty, it applies itself to the rest of the list, returning the two values. If removed is #t , then nothing else must be done and the list is rebuild. Otherwise the function must still remove the element, so it checks if it is equal to the first element of lst and removes it in this case, otherwise, if the first element is a list, calls itself on it.

Finally note that the title is in some way misleading: the function do not remove the last el element from a list, but the rightmost el element in a tree.

Try

(define (remove-last xs)
  (reverse (remove-first (reverse xs) x)))

where (remove-first xs x) will remove the first occurrence of x in xs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM