schemeracket

Level out a list of lists


I'm trying to level out in Racket a list made out of lists and list of lists. The original list looks like:

'(((a 1) (b 2)) (c 3) ((d 4) (e 5)))

I need it to be like:

'((a 1) (b 2) (c 3) (d 4) (e 5))

I've tried with flatten, concatenate, etc and I get different things but not this one:

(define KK '(((a 1)(b 2))(c 3)((d 4)(e 5))))

(map(lambda(x)(if (list? x) x (list x)))(concatenate KK))

'((a 1) (b 2) (c) (3) (d 4) (e 5))

(map(lambda(x)x)(concatenate KK))

'((a 1) (b 2) c 3 (d 4) (e 5))

(map(lambda(x)(if (list? (car x)) (ormap(lambda(y)(when (list? y) y)) x) x))KK)

'((a 1) (c 3) (d 4))

(map(lambda(x)(if (list? (car x)) (andmap(lambda(y)(when (list? y) y)) x) 
x))KK)

'((b 2) (c 3) (e 5))

The closer I got is the last two, but I have missing values, because it is a boolean map. Map packs the result in a single list.

EDIT: My main problem is that the list is created by a function that depending on the input, the output is a single list or a list of 2 to n lists:

Let a list called H be composed of 2 to n elements. Let SPECS be a list made out of lists with the possible combinations of the elements of H that matches condition C. For example:

H='(a 1)

So, being '* a symbol that semantically means a wild car, let all combinations of elements in H to be:

HHs='((* *) (a *)(* 1) (a 1))

So SPECS are the HHs that meets some conditions, for example: '((a )( 1))

(map (lambda(S)(when  (<condition>)(set! NEWSET (append NEWSET S))))SPECS)

If I trace S I see this:

S1: (((*) (-inf.0 9) (2 +inf.0) (*)) ((*) (9 30) (2 +inf.0) (*)))
S2: ((*) (-inf.0 30) (2 +inf.0) (*))
S3: (((*) (-inf.0 30) (2 +inf.0) (no)) ((*) (-inf.0 30) (2 +inf.0) (si)))
S4: (((soleado) (-inf.0 30) (*) (*)) ((nublado) (-inf.0 30) (*) (*)) ((lluvioso) (-inf.0 30) (*) (*)))

So if I pack them in a list, I have:

'((((*) (-inf.0 9) (2 +inf.0) (*)) ((*) (9 30) (2 +inf.0) (*)))
   ((*) (-inf.0 30) (2 +inf.0) (*))
   (((*) (-inf.0 30) (2 +inf.0) (no)) ((*) (-inf.0 30) (2 +inf.0) (si)))
   (((soleado) (-inf.0 30) (*) (*)) ((nublado) (-inf.0 30) (*) (*)) ((lluvioso) (-inf.0 30) (*) (*))))

But I would need instead:

'(((*) (-inf.0 9) (2 +inf.0) (*)) ((*) (9 30) (2 +inf.0) (*))((*) (-inf.0 30) (2 +inf.0) (*))((*) (-inf.0 30) (2 +inf.0) (no)) ((*) (-inf.0 30) (2 +inf.0) (si))((sunny) (-inf.0 30) (*) (*)) ((cloudy) (-inf.0 30) (*) (*)) ((rainy) (-inf.0 30) (*) (*)))

(having the elements of the lists in () it's just a semantic of my algorythm).

Regards


Solution

  • There isn't a one-liner, built-in procedure to solve this for the general case of an arbitrarily nested list. Here's a possible solution using an explicit loop, assuming that the list contains two-element sublists at all levels:

    (define (level-out lst)
      (let loop ([lst (flatten lst)])
        (if (empty? lst)
            '()
            (cons (list (first lst) (second lst))
                  (loop (rest (rest lst)))))))
    

    It works as expected:

    (level-out '(((a 1) (b 2)) (c 3) ((d 4) (e 5))))
    => '((a 1) (b 2) (c 3) (d 4) (e 5))
    
    (level-out '((((((a 1)))))))
    => '((a 1))
    
    (level-out '())
    => '()
    
    (level-out '((a 1) (b 2) (c 3) (d 4) (e 5)))
    => '((a 1) (b 2) (c 3) (d 4) (e 5))