Alex Shroyer
Alex Shroyer

Reputation: 3829

"mostly" flatten a nested list

I have a nested foo where each element is a bar, and I'd like to flatten the foos without flattening the bars.
For example:

(special-flatten (foo (foo (bar 2) (bar 3)) (foo (bar 4) (bar 5)))) ;=>
((bar 2) (bar 3) (bar 4) (bar 5))

Using the normal flatten from racket does not work, because I get (bar 2 bar 3 bar 4 bar 5).

foo can be nested arbitrarily deep.

Is there a racket-y way to do this?

Upvotes: 0

Views: 208

Answers (1)

Alex Knauth
Alex Knauth

Reputation: 8373

If you have a predicate that determines when a sublist shouldn't be flattened, then you can do this.

;; An Element is a value for which element? returns true
;; element? : Any -> Boolean
(define (element? v)
  ...you-have-to-determine-this...)

This element? predicate should answer the question, "What determines when a sublist shouldn't be flattened?" In your case this means things that start with bar such as (bar 2) and (bar 3).

;; An Element is a (cons 'bar Any)
;; element? : Any -> Boolean
(define (element? v)
  (and (pair? v) (equal? (car v) 'bar)))

Once this element? predicate is defined, you can make a flatten function based on it:

;; A NestedFooListofElement is one of:
;;  - Element
;;  - (cons 'foo [Listof NestedFooListofElement])
;; foo-list? : Any -> Boolean
(define (foo-list? v)
  (and (list? v) (pair? v) (equal? (car v) 'foo)))

;; special-flatten : NestedFooListofElement -> [Listof Element]
(define (special-flatten nfle)
  (cond
    [(element? nfle)  (list nfle)]
    [(foo-list? nfle) (append-map special-flatten (rest nfle))]))

Using it:

> (special-flatten '(foo (foo (bar 2) (bar 3)) (foo (bar 4) (bar 5))))
'((bar 2) (bar 3) (bar 4) (bar 5))

Upvotes: 1

Related Questions