How is filter implemented?

Need help on this one using scheme function Return a list containing all elements of a given list that satisfy a given predicate. For example, (filter (lambda (x) (< x 5)) '(3 9 5 8 2 4 7)) should return (3 2 4).

4

5 Answers

filterb - just in case there is already a function called filter.

(define filterb (lambda (pred lst) (cond ((null? lst) '()) ((pred (car lst)) (cons (car lst) (filterb pred (cdr lst)))) (else (filterb pred (cdr lst)))))) 

Here it is, though I am sure it can be made to look nicer.

A simple way to write the filter procedure:

(define (my-filter pred lst) (cond ((null? lst) null) ((pred (first lst)) (cons (first lst) (my-filter pred (rest lst)))) (else (my-filter pred (rest lst))))) 

Notice that I named the procedure my-filter, because a built-in procedure called filter already exists and it's not a good idea to overwrite its definition.

The textbook definition of filter is the (non-tail) recursive one that other posters have shown—and it's important to understand that one. However, if you're writing it as a library function, it's useful to figure out how to do it with tail recursion, so that you don't blow up the stack or heap with long lists:

(define (filter pred? list) (define (filter-aux result current-pair xs) (cond ((null? xs) result) ((pred? (car xs)) (set-cdr! current-pair (cons (car xs) '())) (filter-aux result (cdr current-pair) (cdr xs))) (else (filter-aux result current-pair (cdr xs))))) (let ((init (cons 'throw-me-out '()))) (filter-aux (cdr init) init list))) 

Or, using the let loop syntax:

(define (filter pred? xs) (let ((result (cons 'throw-me-out '())) (xs xs)) (let loop ((current-pair result)) (cond ((null? xs) (cdr result)) ((pred? (car xs)) (set-cdr! current-pair (cons (car xs) '())) (loop (cdr current-pair) (cdr xs))) (else (loop current-pair (cdr xs))))))) 

Try defining filter as an instance of fold-right:

(define (my-filter op xs) (fold-right (lambda (next result) ...) '() xs)) 

Hint: use if and cons

For an alternate tail-recursive filter that doesn't require mutable lists, you could use something like this:

(define (my-filter f lst) (define (iter lst result) (cond ((null? lst) (reverse result)) ((f (car lst)) (iter (cdr lst) (cons (car lst) result))) (else (iter (cdr lst) result)))) (iter lst '())) 

Reverse requires you to walk the list a second time, but it can be implemented in O(n) time with constant stack space on immutable lists, so the overall time is still O(n).

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like