4

I have a nested list of lists occurring in the form of

 A = [[a,b],[c,d]] or [[[a,b],[c,d]]] or [[[[a,b],[c,d]]]] or [[[[[a,b],[c,d]]]]] 

and so on. These forms of A don't occur at the same time.

How can I code to peel the list, no matter how nested A may be, and obtain only:

[a,b] 
[c,d]

I tried this:

def Peel_list(Features):
    try:
        for lon,lat in Features:
            print((lon,lat))
    except:
        for Feature in Features:
            for t_list in Feature:
                for A in t_list:
                    for lon,lat in A:
                        print((lon,lat))
    return()

But it only works for limited A.

jkdev
  • 11,360
  • 15
  • 54
  • 77
  • You can [flatten the list](https://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists) and then build your final result – Devesh Kumar Singh Dec 04 '19 at 05:17
  • 1
    Are you guaranteed to always have lists as the inner element? Never like `[[[a], b, [c, d]]]`? – OneCricketeer Dec 04 '19 at 05:18
  • possibly not an answer . . . can you flatten the list as in this example: https://stackoverflow.com/questions/952914/how-to-make-a-flat-list-out-of-list-of-lists/952946#952946 and then extract [lon, lat] data as pairs of numbers in the generated simple list? (pull out sequential pairs of numbers a, b then c,d then e,f etc) – Stidgeon Dec 04 '19 at 05:21

5 Answers5

4

Generally when we want to deal with a problem of arbitrarily nested objects recursion is a good place to start. Here we want to keep "digging down" until we hit the base case, in our case any non list value. The code looks something like this

test = [1, [3,4],[[5]], [[[6]]]]
peeled = []

def peel(myList, peeled):
    for val in myList:
        if isinstance(val, list):
            if not isinstance(val[0], list):
                peeled.append(val)
            else:
                peel(val, peeled)
        else:
            peeled.append(val)


peel(test, peeled)
print(peeled)

This will give you something like

[1, [3, 4], [5], [6]]

Mitch
  • 3,342
  • 2
  • 21
  • 31
3

A simple approach for the cases that you've provided would be to have a while-loop that continually checks if the size of the list is 1 and modifies your list to contain only the single element (this would get rid of the outermost list).

x = [[[[[a,b],[c,d]]]]]
while len(x) == 1:
    x = x[0]

// result is x = [[1, 2], [3, 4]]

The general approach for when you have elements nested in an arbitrary number of lists would be Mitchel's answer.

Samantha
  • 275
  • 1
  • 12
0

you can also try numpy ravel function on your list, output will be a 1D array.

Desmond
  • 405
  • 1
  • 6
  • 12
0

Here is another recursion based solution:

l1 = [[[['a','b'],['c','d'], [[1,2]]]]]
l2 = [[[[['a','b'],['c','d']]]]]

def f(inp):
    # you can skip this if statement if you are sure that there is no empty nested list 
    if not inp:
        return [[]]
    if (all(isinstance(element, list) for element in inp)):
        return [elem for x in inp for elem in f(x)]
    else:
        return [inp]

With all(), a condition can be checked on every element of an iterable. Results would be:

f(l1) #[['a', 'b'], ['c', 'd'], [1, 2]]
f(l2) #[['a', 'b'], ['c', 'd'], []]
Farzad Vertigo
  • 2,458
  • 1
  • 29
  • 32
0

You can use recursion with a generator:

def flatten(d):
   if all(not isinstance(i, list) for i in d):
      yield d
   else:
      for i in d:
         yield from flatten(i)

print(list(flatten([[[[['a', 'b'], ['c', 'd']]]]])))

Output:

[['a', 'b'], ['c', 'd']]
Ajax1234
  • 69,937
  • 8
  • 61
  • 102