在一个列表中,寻找子列表的数量

4

我在编程项目中遇到了一个问题,需要一些帮助……我认为这是一个有趣的问题 :-)

我正在尝试格式化从GeoJSON获取的类似下面的坐标(由于长度很长,我在此处进行了缩短)。

[[[[-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]]]]


我需要它们最后看起来像这样:
“54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:54.722713302903806,-1.24192061729046:54.722452909315834,-1.241956526315958:54.7271584144655,-1.270237428346303:54.72608036652354,-1.268210325997062,”

目前我已经按照以下代码运行成功,其中变量poly首先被分配一个坐标块,就像上面发布的第一个代码块那样。


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)

然而问题在于,有时候坐标的子列表数量不同于这个示例中的三个,例如以下这样(为了简洁起见再次缩短):

[[[-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]]]

所以我认为我需要一个函数,用于展平嵌套的子列表,该函数重复执行 n 次,直到无法执行而不出错...
对于任何帮助,我将非常感激...

这不是一个有效的语法:-1.241956526315958:54.72242038994674,。那应该是一个字符串吗? - Mark
@Mark Meyer 抱歉,它是一个字符串。我的错。 - osint_alex
@osint_alex,顺便说一句,除了我(https://dev59.com/Hrzpa4cB1Zd3GeqPJ2Sb#63092618),没有人能正确输出您的结果。 - Mark Moretto
@Mark Moretto 哈哈,现在正在查看答案!谢谢!! - osint_alex
7个回答

2

以下是如何使用递归函数:

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))

输出:

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

1
你可以试一下这个:

coordinate_list = [[[[-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]]]]

编辑:调整了coord_pairs函数以捕获所有子列表。

# def flatten(iterable):
#     """Recursive flattening of sublists."""
#     if len(iterable) > 1:
#         res = flatten(iterable[0])
#     else:
#         res = iterable[0]
#     return res


# def coord_pairs(lists):
#     out = ""
#     for item in lists:
#         res = flatten(item)
#         out += ":".join([f"{c[1]},{c[0]}" for c in res])
#     return out


def flatten(iterable):
    """Recursive flattening of sublists."""
    if len(iterable) > 1:
        return flatten(iterable[0])
    else:
        return iterable[0]
    return res


def coord_pairs(lists):
    out = ""
    if len(lists) > 1:
        for item in lists:
            res = flatten(item)
            out += ":".join([f"{c[1]},{c[0]}" for c in res])
    else:
        res = flatten(lists)
        out += ":".join([f"{c[1]},{c[0]}" for c in res])
    return out

# Call function to test output.
coord_pairs(coordinate_list)

输出:

'54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:54.722713302903806,-1.24192061729046:54.722452909315834,-1.24195652631595854.7271584144655,-1.270237428346303:54.72608036652354,-1.268210325997062:54.726854573664205,-1.267390512992676'

@MarkMeyer 是的,我再次查看了它,该函数获取两个子列表中的一个。如果 OP 接受了其他答案,我可能会更新它或删除它。 - Mark Moretto
@MarkMeyer 更新了代码以获取完整的集合。虽然不太优雅,但似乎效果更好。我不知道你是否指的是通过将第二个坐标放在前面来“搞乱顺序”,但 OP 的帖子中所需的输出为 54.722452909315834,-1.241956526315958:54.72242038994674,-1.242505189342398:... - Mark Moretto
可能对顺序弄错了,很抱歉。似乎1.24195652631595854.7271584144655不应该有“:”。 - Mark
这确实是一个奇怪的顺序。不过,你的评论帮助我纠正了我的帖子,所以非常感谢。干杯! - Mark Moretto
嘿,马克,这个可以用于我帖子中的列表,但是对于不同的坐标列表会抛出以下错误:TypeError: object of type 'float' has no len()这些列表的结构看起来像这样:[[[0.35734960034587, 51.691419401103474], [0.360525134769747, 51.69037987969592], [0.362860024738573, 51.69170434483416]]] - osint_alex

1
您可以根据每个元素是否为列表来递归地展平lst。
>>> 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'

0
lst_input = [[[[-1.241956526315958, 54.722452909315834], [-1.242505189342398, 53.72242038994674], [-1.24192061729046, 52.722713302903806], [-1.241956526315958, 54.722452909315834]]], [[[-1.270237428346303, 54.7271584144655], [-1.268210325997062, 54.72608036652354], [-1.267390512992676, 54.726854573664205]]]]

# look inside the current list, if the next element is also a list flatten the current list
while type(next(iter(lst_input))).__name__ == "list":
    lst_input = [item for sublist in lst_input for item in sublist]

# combine the elements of the fully flattened list as string, keep order
string_output = ":".join([", ".join([str(lst_input[j]),str(lst_input[j-1])]) for j in range(1,len(lst_input))])

谢谢你的回答!但是这并没有给我正确的输出格式,并且它产生了非常长的输出,所以我认为它将列表连接了太多次。 - osint_alex

0

试试这个,它应该将所有列表都展开到最后:

origx = [[[[-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]]]]
print(origx)

def flat(x):
    if type(x[0][0]) is list:
        x=[ i for xl in x for i in xl ]
        return flat(x)
    else: 
         return x

def reformat(x):
    s = ""
    for pair in x:
        s=s+str(pair[1])+","+str(pair[0])+":"
    return s[:-1]   


print(reformat(flat(origx)))

输出

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

抱歉,这对我不起作用!我的输出仍然有子列表... - osint_alex
我忘记重新格式化它了。不过这是一个有趣的问题。 - alshaboti

0

好的,我还有另一个答案可以解决这个问题,除了 @Prem Anand 的答案之外!

这不是我的代码,而是来自 realpython.com 用户的答案 -

def flatten(bad):
    good  = []
    while bad:
        e = bad.pop()
        if isinstance(e, list):
            bad.extend(e)
        else:
            good.append(e)
    return good[::-1]
    

poly = [[[[-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]]]]
poly = flatten(poly)
polys_formatted = [str(x) + ',' + str(y) + ':' for x, y in zip(poly[1::2], poly[0::2])]
poly_as_string = ''.join(x for x in polys_formatted)[:-1]
    
print(poly_as_string)

我尝试了各种不同的坐标作为输入,得到的输出都是完美的。


0

为了对比,这里有一种方法根本不尝试遍历数据结构。它立即将其转换为字符串,然后尝试“清理”字符串以呈现您所需的外观:

POST_TRANSLATIONS = str.maketrans({'[': None, ']': None})

def flatten_polys(polygons):
    array = []

    for coordinates in str(polygons).split('], ['):
        array.append(','.join(reversed(coordinates.split(', '))))

    return ':'.join(array).translate(POST_TRANSLATIONS)


if __name__ == "__main__":
    #  Run some tests

    poly_1 = [[[[-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]]]]

    print(flatten_polys(poly_1))

    print()

    poly_2 = [[[-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]]]

    print(flatten_polys(poly_2))

    print()

    poly_3 = [[[0.35734960034587, 51.691419401103474], [0.360525134769747, 51.69037987969592], [0.362860024738573, 51.69170434483416]]]

    print(flatten_polys(poly_3))

输出

> python3 test.py
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

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

51.691419401103474,0.35734960034587:51.69037987969592,0.360525134769747:51.69170434483416,0.362860024738573
>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接