2016-07-08 83 views
4

我從this答案注意到代碼創建一個Python列表理解與if和嵌套打破循環

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

當然,這並沒有考慮到breakif聲明,因此需要顯著長於使用嵌套的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:它是否值得做這個列表理解?唯一的原因是我讀到列表推導通常比嵌套循環快一點。擁有200萬個數據點,每一秒都很重要。

問題2:如果是這樣,我會如何將break聲明納入列表理解?

問題3:在我使用next時,發生了什麼錯誤?

非常感謝您的寶貴時間和善意的幫助。

+0

'next()'用於獲取第一個列表項,並有效地拋出列表的其餘部分。理想情況下,Python只會創建您要求的項目,如果您從未嘗試查看列表的其餘部分,則它從不計算。如果shape(feature ['geometry'))。contains(Point(long_list [i],lat_list [i])))for myrange()中,new_list3 = [next(feature ['properties'] for feature in list) 1000)]'? – TessellatingHeckler

回答

3

列表解析不一定比for循環更快。如果你有這樣一個規律:

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

然後是,該列表理解比一堆.append()速度比較快。但是,你有情有可原的情況。首先,它在next(...)的情況下實際上是一個生成器表達式,因爲它周圍沒有[]

  • 您實際上並未創建列表(因此不使用.append())。你只是獲得一個價值。
  • 您的發電機爲xrange(N)中的每個i的每個功能調用Point(long_list[i], lat_list[i])一次,而循環每個i僅調用一次。
  • 當然,您的生成器表達式不起作用。

爲什麼你的生成器表達式不起作用?因爲它總體上只找到第一個值。另一方面,該循環爲每個i找到第一個值。你看到區別?生成器表達式突破了兩個循環,但for循環僅突破了內部循環。


如果你想在性能略有改善,使用itertools.izip()(或在Python 3只zip()):

from itertools import izip 

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

非常感謝您的回覆。我現在明白了'next'會導致兩個循環的突破,這就是爲什麼它不起作用。我也瞭解如何提高性能。然而,如果你看看我的原代碼,我正在做一個.append()('new_list.append(feature ['properties']); break')。你關於情有可原情況的原始聲明是否仍然存在? – mwolverine

2

我不知道,複雜的列表內涵或發電機表達式是更快如果它們運行相同的算法(例如,訪問相同數量的值),則可以使用嵌套循環。爲了得到明確的答案,您應該嘗試通過兩種方式實施解決方案,並測試以確定哪些數據更快。

至於如何短路內環不是外面一個,你需要把next調用主列表解析裏,有一個單獨的發電機表達它的內部:

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_listlat_list索引從range我使用zip並行迭代它們。

請注意,如果反覆創建對象需要花費太多時間,則可以通過添加另一個嵌套的生成器表達式來簡化該部分代碼,該表達式可創建點並讓您將它們綁定到(可重用)名稱:

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))] 
+0

這真的很有幫助,非常感謝! – mwolverine