将列表组合成元组对 (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)的主要内容,如果未能解决你的问题,请参考以下文章