将列表组合成元组对 (x, y)

Posted

技术标签:

【中文标题】将列表组合成元组对 (x, y)【英文标题】:Combine a list into tuple pairs (x, y) 【发布时间】:2015-06-11 00:44:56 【问题描述】:

我正在尝试合并通过sys.argv 传入的数字对。 示例:

python myscript.py -35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980

我的目标是将这些变成元组中的二元组。 像这样:

((-35.12323,112.76767),(-36.33345,112.76890),(-33.68689,111.8980))

到目前为止,这是我尝试过的,但是当我将结果传递给 Shapely Point 和 Polygon 方法时会出现问题。

from shapely.geometry import Polygon
from shapely.geometry import Point
import sys

def args_to_tuple(list):
    arglist = []

    for coord in list:
        arglist.append(float(coord))

    i = 0
    polylist = []

    for xory in arglist:
        tmp = (arglist[i],arglist[i+1])
        polylist.append(tmp)

    return tuple(polylist)


poly = Polygon(args_to_tuple(sys.argv[3:]))

# xy pair for point is first two sys args
point = Point(args_to_tuple(sys.argv[1:3]))

print point.within(poly) # should result in true, but doesn't
print poly.contains(point) # should result in true, but doesn't

这似乎在 itertools 中很常见,但我似乎在该模块中找不到任何可以让您成对抓取项目的东西。

【问题讨论】:

请编辑问题(特别是标题)以反映,您不想将列表元素组合到元组的列表/元组中,但想了解为什么.within.contains 返回False用你的代码。也许你应该问一个新问题 Alik,我知道我对元组问题的论点出了点问题,而不是 shapely 库,它现在正在工作,因为它被传递了一个有效的元组元组。感谢您的帮助! Iterating over every two elements in a list的可能重复 【参考方案1】:
In [10]: args_str = '-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980'

In [11]: args = map(float, args_str.split())

In [12]: args
Out[12]: [-35.12323, 112.76767, -36.33345, 112.7689, -33.68689, 111.898]

In [13]: zip(args[::2], args[1::2])
Out[13]: [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

zip 可以替换为itertools.izip,它会生成迭代器而不是列表。

【讨论】:

这行得通,我很感激,但这不是更精确地返回“元组列表”吗? TigerhawkT3 的回答也是如此。 @KennyPowers 是的,它返回一个元组列表,但是如果你需要一个包含元组的元组,那么你可以随时这样做tuple(zip(args[::2], args[1::2]))args[::2] 是一个列表切片,它构造一个由奇数元素组成的新列表。阅读更多关于它的信息on SO 感谢您的澄清,我忘记了列表切片的跳过片段......非常有用!最后一个问题,这里的两个答案都包含字符串。当参数被传递到 python 脚本并像 sys.argv[1:] 一样使用时,它们是一个字符串列表,这意味着 str.split() 方法不起作用对于这种情况。 @KennyPowers 如果你有一个点列表,而不是一个字符串,那么只需替换 map 调用中的最后一个参数。无论如何,答案中最重要的部分是关于使用zip 和列表切片,而不是将数据(字符串或字符串列表)转换为浮点数列表【参考方案2】:
def args_to_tuple(lst):
    it = iter(map(float, lst.split()))
    return [(item, next(it)) for item in it]

>>> a = '-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980'
>>> args_to_tuple(a)
[(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

【讨论】:

与此答案相同,输入将是字符串列表,而不是由空格分隔的字符串。输入来自 sys.argv[1:]。有没有一种pythonic方法可以做到这一点并输出一个元组的元组? 然后只使用lst而不是lst.split(),并通过sys.argv[1:] 只有当参数为偶数时才有效,如果奇数则此解决方案抛出异常 @madjardi - 问题指定它们成对出现。数字是二维坐标。【参考方案3】:

我猜 Point 构造函数可能需要 1 对,而不是包含 1 对的元组?为此,您需要进行更改:

point = Point(args_to_tuple(sys.argv[1:3]))

收件人:

point = Point(args_to_tuple(sys.argv[1:3])[0])

或许:

point = Point(*args_to_tuple(sys.argv[1:3])[0])

我不知道形状优美的 API。

至于将参数转换为对元组,您的方法就可以了。但是,如果您想要一个预先打包的便捷解决方案,我会查看 pytoolz 的 partition_all 方法,用于将对组合在一起。还要看看 cytoolz,它努力使这些方法在性能上与 C 相当。

编辑

我注意到你的方法中有一个错误。您没有从 args_to_tuple 方法在循环中增加 i !这是一个修改后的版本,您可以在其中填充 polylist:

polylist = [(arglist[i],arglist[i+1]) for i in xrange(0,len(arglist),2)]

【讨论】:

Point 构造函数是正确的。我试图混搭一些需要 sys args 的东西,并为 Polygon 和 Point 构造函数准备它们,它们分别需要一个元组和一个元组。我能够用很多错误的代码得到我想要的输出,但是如果一个点是否在一个多边形中,我永远无法从检查中得到一个 True 返回,即使使用 shapely 手动检查这些点返回 True。两个构造函数之一不能接受我的转换。 简而言之,我会以 python script.py x y x y x y x y 的格式传入 sys args,其中第一对 xy 浮点数是点,之后的所有内容都是可能具有无限的多边形定义它的点数。 我现在的预感是回到基础并忽略从 sys.argv 读取的部分。只需从包含浮点常量的元组常量创建一个 Point 和 Polygon,并确保 inside 和 contains 方法的行为符合预期。 我同意,这正是我所做的,以及我如何得出这样的结论,即这些调用应该返回 True 值,而不仅仅是通过查看地图。 我在将 sys.argv 转换为对元组的原始方法中发现了一个错误,请参阅我的答案中的编辑。【参考方案4】:
args_list = "-35.12323 112.76767 -36.33345 112.76890 -33.68689 111.8980".split()

您可以压缩相同的迭代器对象以获得您想要的对:

a = (float(x) for x in args_list)
zip(a, a)
# [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

对于 zip 返回的每个元组,next 在同一个迭代器对象上调用两次,以所需的方式配对您的参数。

对于 python 3,您可以只使用映射,因为映射返回一个可迭代的映射对象而不是生成器表达式。

%%python3

a = map(float, args_list)
print(tuple(zip(a, a)))
# ((-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898))

您还可以使用 python 2 的内置 iter 包装 map 返回的列表。

%%python2

a = iter(map(float, args_list)
print zip(a, a)
# [(-35.12323, 112.76767), (-36.33345, 112.7689), (-33.68689, 111.898)]

【讨论】:

我真的很喜欢这个。如果需要,您也可以使用 map() 以获得相同的结果。此外,您可以省略 split() 的参数,因为默认值是空格(但 OP 首先使用 list 切片,所以这有点争议)。【参考方案5】:

感谢大家为我指明正确的方向!这是我的解决方案以供将来参考。不知道为什么我的更糟糕的方法不起作用,但这似乎是 Pythonic 并且足够简单。

from shapely.geometry import Polygon
from shapely.geometry import Point
import sys

#point = Point(38.27269, -120.98145)

# Point
l = map(float, sys.argv[1:3])
point = Point(tuple((l[0],l[1])))


# Polygon
l = map(float, sys.argv[3:])
poly = Polygon(tuple(zip(l[::2], l[1::2])))

# Test
print point.within(poly) # should result in true
print poly.contains(point) # should result in true

【讨论】:

以上是关于将列表组合成元组对 (x, y)的主要内容,如果未能解决你的问题,请参考以下文章

列表随机取2-元组列表

元组对,使用 python 找到最小值

从元组列表中返回具有最小 y 值的元组

将列表转换为元组对[重复]

Python元组列表将第二个元素与唯一的第一个元素合并

数据类型3.5将列表和元组转换为字典