使用if和break嵌套for循环创建Python列表理解

时间:2016-07-08 05:06:36

标签: python list-comprehension nested-loops break

我从this回答了代码

for i in userInput:
    if i in wordsTask:
        a = i
        break

可以通过以下方式编写为列表推导:

next([i for i in userInput if i in wordsTask])

我有一个类似的问题,就是我想在列表理解方面编写以下(从原始问题简化)代码:

 for i in xrange(N):
     point = Point(long_list[i],lat_list[i])
     for feature in feature_list:
         polygon = shape(feature['geometry'])
         if polygon.contains(point):
             new_list.append(feature['properties'])
             break

我希望每个point与功能列表中的单个多边形相关联。因此,一旦找到包含该点的多边形,break将用于移动到下一个点。因此,new_list将具有完全N元素。

我把它写成列表理解如下:

new_list = [feature['properties'] for i in xrange(1000) for feature in feature_list if shape(feature['geometry']).contains(Point(long_list[i],lat_list[i])]

当然,这并没有考虑break语句中的if,因此比使用嵌套for循环花费的时间要长得多。使用上面链接的帖子(我可能不完全理解)的建议,我做了

new_list2 = next(feature['properties'] for i in xrange(1000) for feature in feature_list if shape(feature['geometry']).contains(Point(long_list[i],lat_list[i]))

但是,new_list2的元素少于N个(在我的例子中,N=1000new_list2只有5个元素)

问题1:作为列表理解,是否值得这样做?唯一的原因是我读到列表理解通常比嵌套for循环快一点。每秒有200万个数据点。

问题2:如果是这样,我如何将break语句纳入列表理解?

问题3:以我的方式使用next时出现的错误是什么?

非常感谢你的时间和善意的帮助。

2 个答案:

答案 0 :(得分:3)

列表推导不一定比for循环更快。如果你有一个类似的模式:

some_var = []
for ...:
    if ...:
        some_var.append(some_other_var)

然后是的,列表理解比一堆.append()更快。但是,你有情有可原的情况。首先,在next(...)的情况下,它实际上是一个生成器表达式,因为它周围没有[]

  • 您实际上并未创建列表(因此未使用.append())。你只是得到一个价值。
  • 您的生成器针对Point(long_list[i], lat_list[i])中的每个i的每个功能调用xrange(N)一次,而循环仅为每个i调用一次。
  • 当然,你的生成器表达式不起作用。

为什么你的发电机表达不起作用?因为它只找到整体的第一个值。另一方面,循环查找每个i 的第一个值。你看到了区别?生成器表达式从两个循环中断开,但for循环仅突破内部循环。

如果您希望性能稍有改善,请使用{3}中的itertools.izip()(或仅zip()):

from itertools import izip

for long, lat in izip(long_list, lat_list):
    point = Point(long, lat)
    ...

答案 1 :(得分:2)

我不知道复杂的列表推导或生成器表达式比嵌套循环快得多,如果它们运行相同的算法(例如访问相同数量的值)。要获得明确的答案,您应该尝试以两种方式实施解决方案并进行测试,以确定哪种方法对您的实际数据更快。

至于如何使内循环而不是外循环短路,你需要将next调用放在主列表理解中,并在其中包含一个单独的生成器表达式:< / p>

new_list = [next(feature['properties'] for feature in feature_list
                                       if shape(feature['shape']).contains(Point(long, lat)))
            for long, lat in zip(long_list, lat_list)]

我改变了另外一件事:而不是使用long_list使用lat_list进行迭代,使rangezip的索引编入索引他们并行。

请注意,如果反复创建Point个对象需要花费太多时间,可以通过添加另一个创建点的嵌套生成器表达式来简化代码的这一部分,并允许您将它们绑定到(可重复使用)名称:

new_list = [next(feature['properties'] for feature in feature_list
                                       if shape(feature['shape']).contains(point))
            for point in (Point(long, lat) for long, lat in zip(long_list, lat_list))]