Vic
Vic

Reputation: 109

Remove parentheses from lists in Racket

I am trying to write a code that removes parentheses from each top level element of the list. For example, the input '( (1 2) (3 4) ) will produce '(1 2 3 4) and the input '((x (y)) z) should produce '(x (y) z).

Is there a way to recognize pairs of parentheses? I was thinking I could find pairs of parentheses and remove them, but I'm not sure how to do that and also how to only remove from the top element.

Upvotes: 1

Views: 3904

Answers (2)

assefamaru
assefamaru

Reputation: 2789

Without using append or map, you can define mutually recursive functions to do what you want, as follows:

(define (unwrap lst)
  (if (null? lst)
      '()
      (my-append (car lst) (cdr lst))))

(define (my-append lhs rhs)
  (cond
    [(null? lhs)
     (unwrap rhs)]
    [(pair? lhs)
     (cons (car lhs)
           (my-append (cdr lhs) rhs))]
    [else
     (cons lhs (unwrap rhs))]))

For example:

> (unwrap '((1 2) (3 4 (5 (6)))))
'(1 2 3 4 (5 (6)))
> (unwrap '((x (y)) z))
'(x (y) z)

Upvotes: 0

Brendan Cannell
Brendan Cannell

Reputation: 679

The pattern "I am trying to (do something to) each top level element of the list" is a sure sign that map will be involved. Also, one big clue is in your first example case:

'((1 2) (3 4))  =>  '(1 2 3 4)

That's just append*!

(append* '((1 2) (3 4)))  =>  '(1 2 3 4)

But that's not the case for '((x (y)) z) => '(x (y) z).

(append* '((x (y)) z))  =>  '(x (y) . z)

If you think about it, append* is very close to what you want: it unwraps one level of parens from each element in a list. Problem is, some of the elements in your input aren't lists, so there's nothing to unwrap.

We could fix that by just wrapping each non-list element in a singleton list, so that '((x (y)) z) becomes '((x (y)) (z)). And then we can use append*:

(append* '((x (y)) (z)))  =>  '(x (y) z)

This is where map comes handy. map is a function that takes a function (f) and a list (lst) and returns a new list made by applying f to each element of lst. For example:

(map symbol? '(a 2 b c 5))  =>  '(#t #f #t #t #f)

Suppose you wrote a function that takes one argument and either returns it unaltered if it's a list, or else wraps it up as a singleton list if it's not. Let's call it maybe-wrap. Then you could map maybe-wrap over your input, and the result could be passed to append*:

(define (remove-parens lst)
  (append* (map maybe-wrap lst)))

I'll leave it to you to write maybe-wrap.

Upvotes: 2

Related Questions