У меня есть очень простая подпрограмма python, которая включает в себя циклирование через список из примерно 20 000 координат широты, долготы и вычисление расстояния каждой точки до контрольной точки.
def compute_nearest_points( lat, lon, nPoints=5 ):
"""Find the nearest N points, given the input coordinates."""
points = session.query(PointIndex).all()
oldNearest = []
newNearest = []
for n in xrange(nPoints):
oldNearest.append(PointDistance(None,None,None,99999.0,99999.0))
newNearest.append(obj2)
#This is almost certainly an inappropriate use of deepcopy
# but how SHOULD I be doing this?!?!
for point in points:
distance = compute_spherical_law_of_cosines( lat, lon, point.avg_lat, point.avg_lon )
k = 0
for p in oldNearest:
if distance < p.distance:
newNearest[k] = PointDistance(
point.point, point.kana, point.english, point.avg_lat, point.avg_lon, distance=distance
)
break
else:
newNearest[k] = deepcopy(oldNearest[k])
k += 1
for j in range(k,nPoints-1):
newNearest[j+1] = deepcopy(oldNearest[j])
oldNearest = deepcopy(newNearest)
#We're done, now print the result
for point in oldNearest:
print point.station, point.english, point.distance
return
Я изначально написал это на C, используя тот же подход, и он отлично работает там и в основном мгновен для nPoints <= 100. Поэтому я решил перенести его на python, потому что я хотел использовать SqlAlchemy для создания других вещей.
Сначала я портировал его без инструкций deepcopy, которые теперь пересиливают метод, и это привело к тому, что результаты были "нечетными" или частично некорректными, потому что некоторые из точек просто копировались как ссылки (я думаю, я думаю? ) - но это было все еще довольно быстро, как версия C.
Теперь, когда добавляются вызовы deepcopy, процедура делает это правильно, но это повлекло за собой чрезвычайное снижение производительности и теперь занимает несколько секунд, чтобы выполнить ту же работу.
Это похоже на довольно распространенную работу, но я явно не делаю этого питоническим способом. Как я должен делать это, чтобы все еще получить правильные результаты, но не нужно включать всюду?
EDIT:
Я попал в гораздо более простое и быстрое решение,
def compute_nearest_points2( lat, lon, nPoints=5 ):
"""Find the nearest N points, given the input coordinates."""
points = session.query(PointIndex).all()
nearest = []
for point in points:
distance = compute_spherical_law_of_cosines( lat, lon, point.avg_lat, point.avg_lon )
nearest.append(
PointDistance(
point.point, point.kana, point.english, point.avg_lat, point.avg_lon, distance=distance
)
)
nearest_points = sorted(nearest, key=lambda point: point.distance)[:nPoints]
for item in nearest_points:
print item.point, item.english, item.distance
return
Итак, в основном я просто делаю полную копию ввода и добавляю новое значение - расстояние от контрольной точки. Затем я просто применил "отсортированный" к результирующему списку, указав, что ключ сортировки должен быть свойством расстояния объекта PointDistance.
Это намного быстрее, чем использование deepcopy, хотя, признаюсь, я действительно не понимаю, почему. Я полагаю, что до эффективных C-реализаций python "отсортирован"?