(Racket) Return a sublist of a list that satisfy a condition

Viewed 361

I'm having trouble writing a function that returns a sublist of pairs that satisfy a condition.

Current code:

(define lst1 '((a . 8)(b . 3)(c . 1)(d . 9)(e . 4)))

(define (letter t)
  (caar t))

(define (numb p)
  (cdar p))

(define (satisfy? c? lst)
  (cond
    [(or (c? (letter lst)) (c? (numb lst))) #t]
    [else #f]))

(define (find-sublist c? lst)
  (cond
    [(satisfy? c? lst) (cons (car lst) (find-sublist c?(cdr lst)))]
    [else (find-sublist c? (cdr lst))]))

Console input:

(find-sublist (lambda(x) (> (numb x) 3)) lst1)

Wanted output:

'((a . 8)(d . 9)(e . 4))

My current input consists of contract violations of either cons or pair

car: contract violation   
     expected: pair?   
     given: '()

cdar: contract violation
      expected: (cons/c pair? any/c)
      given: 'a
1 Answers

There are a couple of issues with your code:

  • The letter and numb procedures operate on a list element, not on a list, so they should be just car and cdr.
  • You forgot the base case, what should happen when the list is empty?
  • Don't put () around lst, it's not a procedure.
  • And more importantly: your satisfy? procedure attempts to operate on the letter or on the number, but in the lambda you already extracted the number. The solution is just to get rid of this procedure (or alternatively, don't extract the number in the lambda, but then you'll have to test if the lambda's argument is a number before applying the condition.)

This should fix the issues:

(define (letter t)
  (car t))

(define (numb p)
  (cdr p))

(define (find-sublist c? lst)
  (cond
    [(null? lst) '()]
    [(c? (car lst)) (cons (car lst) (find-sublist c? (cdr lst)))]
    [else (find-sublist c? (cdr lst))]))

It works as expected:

(define lst1 '((a . 8) (b . 3) (c . 1) (d . 9) (e . 4)))
(find-sublist (lambda (x) (> (numb x) 3)) lst1)
=> '((a . 8) (d . 9) (e . 4))

FYI you reimplemented the built-in filter procedure. You should use existing procedures whenever possible ;)

(filter (lambda (x) (> (numb x) 3)) lst1)
=> '((a . 8) (d . 9) (e . 4))
Related