简体   繁体   中英

Flatten top-level sublists in Scheme

I am working my first project in scheme and have come across an issue. In part of my requirements, I am required to append all top-level sublists (eg '((1 2)(3 4 (5 6))) -> (1 2 3 4 (5 6)) and '((1 2 3)(4 5)) -> (1 2 3 4 5) I've managed to get it working down to a single list, but this flattens all levels:

 (cond
     ((null? lst)
         lst)        
     ((list? lst)
         (append2(append-subs(car lst))(append-subs(cdr lst))))
     (else
         (cons lst '())))

Variations of this (eg. (else lst) run the error "object 6, passed as first arg to cdr, is not correct type" . Another method I attempted is as follows:

    (cond
        ((null? lst)
            lst)        
        ((>= (len (cdr lst)) 0)
            (append2(append-subs(car (list lst)))(append-subs(cdr (list lst)))))
        (else
            lst)

Which infinitely loops. I'm at a bit of a stand still, so any help would be greatly appreciated. (Note: Use of functions other than those used here is forbidden. Limited to list, list?, if, cond, null? ...)

Your list '(e1 e2 e3) would be like this:

(cons e1 (cons e2 (cons e3 '())))

or if you like dotted notation:

'(e1 . (e2 . (e3 . ())))

Where en is eiter #f or #t for (list? en) Your assignment is to cons en onto the recursion with the same level while with a list you need to append the two.

Here is a general idea how to implement it with level as an input parameter:

;;; flatten a list a certain levels
;;; level of zero is identity
(define (flatten-level level lst)
  (cond ((or (zero? level)
             (null? lst))
         lst)
        ;; pair? is faster but will fall through for dotted
        ((list? (car lst)) 
         (append (flatten-level <??> <??>)
                 (flatten-level <??> <??>)))
        (else 
         (cons <??>
               (flatten-level <??> <??>)))))

(flatten-level 0  '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> ((1 2) (3 (((4 . 3))) (5 (6))) . 7) (aka identity)
(flatten-level 1  '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (((4 . 3))) (5 (6)) . 7)
(flatten-level 99 '((1 2)(3 (((4 . 3))) (5 (6))) . 7))
; ==> (1 2 3 (4 . 3) 5 6 . 7)

How about appending all elements of the top list:

(define (flatten-top-level lst)
  (apply append lst))

Which is practically the definition of append*

If '(a (b) (cf)) is a valid input, (first element not a list) then you can try:

(define (flatten-top-level lst)
  (apply append
         (map (lambda (e) (if (list? e)
                              e 
                              (list e))) ;make a list from the non-list element
         lst)))

2nd option: Fold it!

(define (flatten-top-level lst)
  (foldr append '() lst))

For a list (abcd) where a, b, c, d are sub-lists; it is equal to:

(append a (append b (append c (append d '()))))

Extra : this is tail recurssive and therefore runs in linear time :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM