Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find number of sublists in list of many lists

I've got a little stuck on something on a project I'm coding and would really appreciate some help... I think it's an interesting problem too :-)

I'm trying to format coordinates that come like the below from geojson (I've shortened to paste it here as they are very long).

[[[[-1.241956526315958, 54.722452909315834], [-1.242505189342398, 54.72242038994674], [-1.24192061729046, 54.722713302903806], [-1.241956526315958, 54.722452909315834]]], [[[-1.270237428346303, 54.7271584144655], [-1.268210325997062, 54.72608036652354], [-1.267390512992676, 54.726854573664205]]]]

I need them to end up looking like this:

“54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:54.722713302903806,-1.24192061729046:54.722452909315834,-1.241956526315958:54.7271584144655,-1.270237428346303:54.72608036652354,-1.268210325997062,”

Currently I've got this working with the below code where the variable poly is first assigned to a block of co-ordinates like the first one posted above.


def threetimes(func):
    """Executes the function on its own output two times."""
    @functools.wraps(func)
    def wrapper_three_times(*args, **kwargs):
        value = func(*args, **kwargs)
        value2 = func(value)
        value3 = func(value2)
        return value3
    return wrapper_three_times

def swap_pairs(poly):
    """
    Turns a list like this [1, 2, 3, 4] into [2, 1, 4, 3]
    :param polys: list
    :return: list
    """

    for i in range(0, len(poly) - 1, 2):
        poly[i], poly[i + 1] = poly[i + 1], poly[i]

    return poly

@threetimes
def flatten_polys(poly):
    """
    Turns geojson polygons into flat lists.
    :param poly: List of three lists; standard geojson polygon or multipolygon format.
    :return: flat list of the polygon co-ordinates.
    """

    flat_poly = [item for sublist in poly for item in sublist]

    return flat_poly

poly = flatten_polys(poly)
poly = swap_pairs(poly)
polys_formatted = [str(x) + ',' + str(y) + ':' for x, y in zip(poly[0::2], poly[1::2])]
polys_formatted[-1] = polys_formatted[-1].replace(':', '')
poly_as_string = ''.join(x for x in polys_formatted)

The problem however is that sometimes the co-ordinates have a different number of sublists rather than three as in the example here, i.e. they look like this (again truncated for brevity's sake):

[[[-0.109373710729991, 51.42315755917108], [-0.105987341539958, 51.422576811743276], [-0.096906133161734, 51.422667109533435], [-0.094346733695295, 51.422818864663064], [-0.092734433338077, 51.42253994327862], [-0.088190383828824, 51.419927269261336], [-0.086425687184976, 51.419305849976176], [-0.082346001337163, 51.419771533877956], [-0.078548643992427, 51.41984782473602], [-0.080993694631571, 51.417101046706534], [-0.080475514860821, 51.415566497757084]]]

So what I think I need is a function to flatten nested sublists that repeats itself n times until it can no longer execute without an error...

I'll be very grateful for any assistance...

like image 981
osint_alex Avatar asked Sep 02 '25 07:09

osint_alex


2 Answers

Here is how you can use a recursive function:

lst = [[[[-1.241956526315958, 54.722452909315834], [-1.242505189342398, 54.72242038994674], [-1.24192061729046, 54.722713302903806], [-1.241956526315958, 54.722452909315834]]], [[[-1.270237428346303, 54.7271584144655], [-1.268210325997062, 54.72608036652354], [-1.267390512992676, 54.726854573664205]]]]

cor = []

def func(lst):
    for a in lst:
        if isinstance(a,list):
            if not any(isinstance(i, list) for i in a):
                cor.append(f"{a[1]},{a[0]}")
            func(a)
            
func(lst)
print(':'.join(cor))

Output:

54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:54.722713302903806,-1.24192061729046:54.722452909315834,-1.241956526315958:54.7271584144655,-1.270237428346303:54.72608036652354,-1.268210325997062:54.726854573664205,-1.267390512992676
like image 92
Ann Zen Avatar answered Sep 04 '25 19:09

Ann Zen


You can recursively flatten the lst depending on if each element is a list or not

>>> from itertools import chain
>>> lst_input = [[[[-1.241956526315958, 54.722452909315834], [-1.242505189342398, 54.72242038994674], [-1.24192061729046, 54.722713302903806], [-1.241956526315958, 54.722452909315834]]], [[[-1.270237428346303, 54.7271584144655], [-1.268210325997062, 54.72608036652354], [-1.267390512992676, 54.726854573664205]]]]
>>> 
>>> 
>>> flatten = lambda lst: [i for e in lst for i in (chain(reversed(flatten(e)), [':'])  if isinstance(e, list) else [e])]
>>> lst = flatten(lst_input)
>>> lst
[':', 54.722452909315834, -1.241956526315958, ':', 54.72242038994674, -1.242505189342398, ':', 54.722713302903806, -1.24192061729046, ':', 54.722452909315834, -1.241956526315958, ':', ':', ':', 54.7271584144655, -1.270237428346303, ':', 54.72608036652354, -1.268210325997062, ':', 54.726854573664205, -1.267390512992676, ':', ':']
>>> 
>>> ','.join(map(str, lst)).strip(':,').replace(',:,', ':')
'54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:54.722713302903806,-1.24192061729046:54.722452909315834,-1.241956526315958:::54.7271584144655,-1.270237428346303:54.72608036652354,-1.268210325997062:54.726854573664205,-1.267390512992676'
like image 23
Prem Anand Avatar answered Sep 04 '25 21:09

Prem Anand