Filter function for nested lists in dr racket - racket

I am looking for a function that does what "filter" is used for, but without using filter. On top, it should also filter nested lists.
E. g. list ( 1 2 (list 3 'a 'b) 3 4) should return list (1 2 (list 3) 3 4).
I already have the function to filter. My thought is, that I have to distinguish in the beginning of the function, if first lst is a list itself.
What I got so far is:
(define (my-filter pred lst)
(cond ((null? lst) null) ;;(after this I would try to test if it is a list itself, but I am not sure how)
((pred (first lst))
(cons (first lst) (my-filter pred (rest lst))))
(else (my-filter pred (rest lst)))))

As it has been said in the comments, a possible solution is:
(define (my-filter pred lst)
(cond [(null? lst) null]
[(list? (first lst)) (cons (my-filter pred (first lst))
(my-filter pred (rest lst)))]
[else (if (pred (first lst))
(cons (first lst) (my-filter pred (rest lst)))
(my-filter pred (rest lst)))]))
Example
> (my-filter number? '(1 a 2 (3 (b 4) c) 5 6 d 7))
'(1 2 (3 (4)) 5 6 7)
> (my-filter (lambda (x) (not (number? x))) '(1 a 2 (3 (b 4) c) 5 6 d 7))
'(a ((b) c) d)

Related

Filter out any value other than a number

I am trying to come up with a procedure that filters out any value other than a number. For example:
'(1 2 (a) 3) => '(1 2 () 3) or '(1 2 (a 10 11 (b 2 (c))) 3) => '(1 2 (10 11 (2 ())) 3)
This is what I have so far but it doesn't really work because it replaces the non numbers with an empty list instead of nothing:
(define (filter-numbers lst)
(if (null? lst)
'()
(if (list? lst)
(cons
(filter-numbers (car lst))
(filter-numbers (cdr lst)))
(if (number? lst)
lst
'())))
)
The procedure outputs the following:
> (filter-numbers '(1 2 (a) 3))
'(1 2 (()) 3)
instead of: '(1 2 () 3)
You need to check if an element in a sublist is a number before deciding to cons it to the output or not. I think it's easier if we restructure the code a bit; also some tips: don't use list?, prefer pair? as it's faster (unlike list? it doesn't have to traverse the whole list). And prefer cond instead of nesting ifs, your code will be easier to read. This is what I mean:
(define (filter-numbers lst)
(cond ((null? lst) lst)
((not (pair? (car lst)))
; check the element while still in a list, if we wait
; until we reach an atom it's too late to filter it out
(if (number? (car lst))
; either add the element to the output or skip it
(cons (car lst) (filter-numbers (cdr lst)))
(filter-numbers (cdr lst))))
(else (cons
(filter-numbers (car lst))
(filter-numbers (cdr lst))))))
It works as expected:
(filter-numbers '(1 2 (a) 3))
=> (1 2 () 3)
(filter-numbers '(1 2 (a 10 11 (b 2 (c))) 3))
=> '(1 2 (10 11 (2 ())) 3)

trying to write a function that returns every third element in a list in racket language

Trying to write a function that returns every third element in a list
including the first element in racket. All I get now is my code blowing up with a first: contract violation
expected: (and/c list? (not/c empty?))
given: 4
(define l (list 1 2 3 4 5 6 7 8 9))
(define (skipper lst)
(if (null? lst)
'()
(cons (first lst)
(skipper (car (cdr (cdr (cdr lst))))))))
(skipper l)
The problem was just the car around cdddr.
(define l (list 1 2 3 4 5 6 7 8 9))
(define (skipper lst)
(if (null? lst)
'()
(cons (first lst)
(skipper (if (< (length lst) 3)
'()
(cdddr lst))))))
(skipper l) ;; '(1 4 7)
Generalized Solution
(define (my-cdr lst) ;; `cdr` behaving like in common-lisp: (cdr '()) -> '()
(cond ((null? lst) '())
(else (cdr lst))))
(define (multi-cdr lst k) ;; apply `my-cdr` k-times on `lst`
(cond ((zero? k) lst)
(else (multi-cdr (my-cdr lst) (- k 1)))))
(define (skipper lst k)
(if (null? lst)
'()
(cons (first lst)
(skipper (multi-cdr lst k) k))))
Test it:
(skipper l 3) ;; '(1 4 7)
(skipper l 4) ;; '(1 5 9)
(skipper l 2) ;; '(1 3 5 7 9)
(skipper l 1) ;; '(1 2 3 4 5 6 7 8 9)
The issue is that you cannot call (cdr (cdr (cdr lst))) when lst has less than 3 elements.
You tagged this with racket, so I'm going to show you a solution using match
(define (skipper l)
(match l
;; some element and at least 3 more
((list a rest ..3)
(cons a (skipper (cddr rest))))
;; at least one element
((cons a _)
(list a))
;; otherwise
(else
empty)))
(skipper '())
;; '()
(skipper '(0))
;; '(0)
(skipper '(0 1 2 3 4 5 6 7))
;; '(0 3 6)
(skipper '(0 1 2 3 4 5 6 7 8 9))
;; '(0 3 6 9)
This solution doesn't use length which unnecessarily computes the length of the list

How do you transform a list of numbers into a list of three-digit numbers in Racket?

For example, '(1 2 3 4 5 6 7 8 9) would transform into '(123 456 789). I tried to find a recursive way of doing this but failed.
For example
(define (f lst)
(if (null? lst)
null
(cons (+ (* 100 (car lst))
(* 10 (cadr lst))
(caddr lst))
(f (cdddr lst)))))

Racket. Make a list of pairs from a list

I want to make a list of pairs starting from a list, the cdr will be always the same. For example, (make-pair '(1 2 3 4 5)) should return '((1.a)(2.a)(3.a)(4.a)(5.a)).
This is the code i am developing, but it doesn't work and I don't know how to debug it.
(define (make-pair lst)
(if (null? (car lst))
'()
(cons ((car lst) ".a")
(make-pair (cdr lst)))))
Thank you in advance!
You have a couple of errors:
(define (make-pair lst)
(if (null? (car lst)) ; - the base case is when the list is null
'()
(cons ((car lst) ".a") ; - there's a missing cons
; - `a` appears to be a symbol, not a string
; - that's not how we create a dotted pair
; - the surrounding `()` are misplaced
(make-pair (cdr lst)))))
This is the right way:
(define (make-pair lst)
(if (null? lst)
'()
(cons (cons (car lst) 'a)
(make-pair (cdr lst)))))
Or even better, use built-in procedures:
(define (make-pair lst)
(map (lambda (n) (cons n 'a))
lst))
Either way, it works as expected:
(make-pair '(1 2 3 4 5))
=> '((1 . a) (2 . a) (3 . a) (4 . a) (5 . a))

racket postfix to prefix

I have a series of expressions to convert from postfix to prefix and I thought that I would try to write a program to do it for me in DrRacket. I am getting stuck with some of the more complex ones such as (10 (1 2 3 +) ^).
I have the very simple case down for (1 2 \*) → (\* 1 2). I have set these expressions up as a list and I know that you have to use cdr/car and recursion to do it but that is where I get stuck.
My inputs will be something along the lines of '(1 2 +).
I have for simple things such as '(1 2 +):
(define ans '())
(define (post-pre lst)
(set! ans (list (last lst) (first lst) (second lst))))
For the more complex stuff I have this (which fails to work correctly):
(define ans '())
(define (post-pre-comp lst)
(cond [(pair? (car lst)) (post-pre-comp (car lst))]
[(pair? (cdr lst)) (post-pre-comp (cdr lst))]
[else (set! ans (list (last lst) (first lst) (second lst)))]))
Obviously I am getting tripped up because (cdr lst) will return a pair most of the time. I'm guessing my structure of the else statement is wrong and I need it to be cons instead of list, but I'm not sure how to get that to work properly in this case.
Were you thinking of something like this?
(define (pp sxp)
(cond
((null? sxp) sxp)
((list? sxp) (let-values (((args op) (split-at-right sxp 1)))
(cons (car op) (map pp args))))
(else sxp)))
then
> (pp '(1 2 *))
'(* 1 2)
> (pp '(10 (1 2 3 +) ^))
'(^ 10 (+ 1 2 3))
Try something like this:
(define (postfix->prefix expr)
(cond
[(and (list? expr) (not (null? expr)))
(define op (last expr))
(define args (drop-right expr 1))
(cons op (map postfix->prefix args))]
[else expr]))
This operates on the structure recursively by using map to call itself on the arguments to each call.