2016-07-08 4 views
4

я заметил из this ответа, что кодСоздание списка понимания Python с, если и порвать с вложенным для петель

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 заявления, и, следовательно, значительно больше, чем требуется для использования вложенных циклов. Пользуясь советами из вышеприведенного-сшитый пост (который я, вероятно, не в полной мере понять), я сделал

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=1000 и new_list2 имели только 5 элементов)

Вопрос 1: Стоит ли это делать как понимание списка? Единственная причина в том, что я читал, что понимание списков обычно немного быстрее, чем вложенные для циклов. С 2 миллионами точек данных каждая секунда считается.

Вопрос 2: Если да, то как я могу включить заявление break в понимании списка?

Вопрос 3: Какова была ошибка при использовании next в том, как я это делал?

Благодарим вас за ваше время и помощь.

+0

'next()' используется, чтобы взять первый элемент списка и эффективно выбросить остальную часть списка. В идеале, Python создает только те элементы, которые вы просите, и если вы никогда не пытаетесь просмотреть остальную часть списка, он никогда не вычисляется. Что касается 'new_list3 = [next (функция ['properties'] для функции в feature_list, если shape (feature ['geometry']) содержит (Point (long_list [i], lat_list [i]))) для i в xrange (1000)] '? – TessellatingHeckler

ответ

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 выходит из внутреннего.


Если вы хотите небольшое улучшение производительности, используйте itertools.izip() (или просто zip() в Python 3):

from itertools import izip 

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

Большое вам спасибо за ваш ответ. Теперь я понимаю, что 'next' вызывает разрыв обоих циклов, поэтому он не работает. Я также понимаю, как izip может повысить производительность. Однако, если вы посмотрите на мой исходный код, я делаю именно файл .append() ('new_list.append (функция ['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_list и lat_list с индексами из range Я использую zip для параллельной итерации по ним.

Обратите внимание, что если создание объектов Point снова и снова заканчивается занять слишком много времени, вы можете упорядочить эту часть кода, добавив еще одно вложенное выражение генератора, которое создает точки и позволяет привязать их к (многоразовому) name:

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

 Смежные вопросы

  • Нет связанных вопросов^_^