kin*_*ion 4 python list-comprehension python-3.x
我有两个相同长度的列表.我想检查一个列表中的条件.如果条件为真,则在另一个列表上运行一个非常大的内存/处理密集型函数.
我的第一次尝试是这样的:
records = [(a, deadly_func(b)) for a, b in zip(listA, listB) if a == "condition"]
Run Code Online (Sandbox Code Playgroud)
这立即分配了我桌面上的所有内存,并在我杀了它之前继续了一段时间.显然,它在listB中的所有30,000个项目上运行了deadly_func(b),而意图是使用'if'语句将listB过滤到大约30个项目.
我能够制作一个有效的版本:
records = [(a, i) for a, i in zip(listA, range(len(listB)) if a == "condition"]
records = [(a, deadly_func(listB[i]) for a, i in records]
Run Code Online (Sandbox Code Playgroud)
为什么我的第一次尝试不起作用?是否有更多的pythonic方式使这项工作?
编辑:谢谢你的回复.这是两个版本的实际代码
不工作:
import shapefile, shapely.geometry as shpgeo
lat = 42.3968243
lon = -71.0313479
sf = shapefile.Reader("/opt/ziplfs/tl_2014_us_zcta510.shp")
records = [(r[0], shpgeo.shape(s.__geo_interface__)) for r, s in zip(sf.records(), sf.shapes()) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]
Run Code Online (Sandbox Code Playgroud)
haversine()是一个用户自制的半正弦函数,取两对lat和long并以km为单位返回距离.
from math import sqrt, sin, cos, radians, asin
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees). Return is in kilometers
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return c * r
Run Code Online (Sandbox Code Playgroud)
shapefile('tl_2014_us_zcta510.shp')是美国人口普查局的所有拉链码.如果你真的喜欢shapefile,请在这里下载,你的硬盘上有800 MB,你不知道该怎么做.
此脚本应返回一个元组列表,表示美国的所有邮政编码,其中心位于距离马萨诸塞州切尔西10公里的范围内.
对于工作版本,将记录行替换为:
records = [(r[0], i) for r, i in zip(sf.records(), range(len(sf.records()))) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]
shapes = [shpgeo.shape(sf.shape(i).__geo_interface__) for r, i in records]
Run Code Online (Sandbox Code Playgroud)
我做了一些时间测试.'非工作'版本:
$ python test.py
Time Elapsed: 0:00:14.221533
$ python test.py
Time Elapsed: 0:00:14.637827
$ python test.py
Time Elapsed: 0:00:14.253425
Run Code Online (Sandbox Code Playgroud)
和工作版本:
$ python test.py
Time Elapsed: 0:00:01.887987
$ python test.py
Time Elapsed: 0:00:01.886635
$ python test.py
Time Elapsed: 0:00:01.982547
Run Code Online (Sandbox Code Playgroud)
也许每个人都不会"致命",但重复30k次时会很重要.
没有repro?此代码并不会运行deadly_func上的所有元素listB.只是那些对应的listA值是True:
listA = [True, False, True, False]
listB = [1, 2, 3, 4]
def deadly_func(x):
print("Called with {}".format(x))
return x
print([(a, deadly_func(b)) for a, b in zip(listA, listB) if a])
# Output:
# Called with 1
# Called with 3
# [(True, 1), (True, 3)]
Run Code Online (Sandbox Code Playgroud)
编辑
基于更新的问题,我的猜测是sf.shapes()昂贵的部分.因此sf.shape(i),仅调用所需元素的子集会更有效.
如果我的猜测是正确的,这应该是诀窍:
records = [(r[0], shpgeo.shape(sf.shape(i).__geo_interface__)) for i, r in enumerate(sf.records()) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]
Run Code Online (Sandbox Code Playgroud)
(当然,这主要是你已经做过的.)
| 归档时间: |
|
| 查看次数: |
86 次 |
| 最近记录: |