Как ускорить цикл python
Я просмотрел несколько фактов на нескольких сайтах, и никто из них не дал мне решения.
Эта часть кода занимает более 5 секунд для запуска:
for i in xrange(100000000):
pass
Я работаю над цельной оптимизационной задачей, и мне нужно использовать алгоритм O (n log n) edit: алгоритм O (n²/4), где n означает все элементы матрицы, т.е., в следующем коде n * m = 10000. Таким образом, для матрицы 100 * 100 с 10000 элементами это приведет к почти 25000000 итераций....
Его код можно суммировать следующим образом:
m = 100
n = 100
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]:
return [i, j], [i2, j2]
Должен ли я отказаться от Python и вернуться на Java или на C?
Я работаю с Python 2.7 и Psyco недоступен. PyPy не поддерживает Tkinter из коробки, и я использую Tkinter.
Итак, улучшат ли скорость цикла? Существуют ли другие решения?
Ответы
Ответ 1
Не самый красивый стиль кодирования, но отчаянные времена требуют отчаянного кодирования. Попробуйте превратить ваши вложенные вложенные петли в одно большое выражение генератора:
try:
i,j,i2,j2 = ((i,j,i2,j2)
for i in xrange(m)
for j in xrange(n)
for i2 in xrange(i + 1, m)
for j2 in xrange(j + 1, n)
if myarray[i][j] == myarray[i2][j2] and
myarray[i2][j] == myarray[i][j2]).next()
return [i,j],[i2,j2]
except StopIteration:
return None
Ответ 2
Вы все еще можете использовать нотацию python и иметь скорость C, используя проект Cython.
Первым шагом было бы преобразовать цикл в цикл C: он автоматически выполняется путем ввода всех переменных, используемых в цикле:
cdef int m = 100
cdef int n = 100
cdef int i, j, i2, j2
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
В следующей части было бы еще лучше, если бы myarray был чистым массивом C, а затем отсутствовал богатый интерфейс python или доступ к массиву. С помощью вашего массива python вы можете удалить богатый comparaison, выполнив собственный comparaison (если у вас двойной размер в вашем массиве):
cdef double a, b, c, d
a = myarray[i][j]
b = myarray[i2][j2]
c = myarray[i2][j]
d = myarray[i][j2]
if a == b and c == d:
return [i, j], [i2, j2]
Вы можете увидеть, как оптимизация выполняется, запустив cython -a yourfile.pyx
, затем откройте yourfile.html
generate. Вы увидите, как Cython оптимизировал ваш код и удалил служебные данные Python.
Ответ 3
Прошу прощения, но это не вопрос оптимизации. Независимо от того, какой язык или реализация вы выберете, этот алгоритм не O(n*log n)
в худшем и среднем случае. Возможно, вы захотите прочитать как работает нота Big-O и разработать лучший алгоритм.
Ответ 4
Извините, генератор expr не работает. Вот другая схема, которая сначала подбирает все одинаковые значения, а затем ищет прямоугольные группы:
from collections import defaultdict
from itertools import permutations
def f3(myarray):
tally = defaultdict(list)
for i,row in enumerate(myarray):
for j,n in enumerate(row):
tally[n].append((i,j))
# look for rectangular quads in each list
for k,v in tally.items():
for quad in permutations(v,4):
# sort quad so that we can get rectangle corners
quad = sorted(quad)
(i1,j1),(i2,j2) = quad[0], quad[-1]
# slice out opposite corners to see if we have a rectangle
others = quad[1:3]
if [(i1,j2),(i2,j1)] == others:
return [i1,j1],[i2,j2]
Ответ 5
Я посмотрел несколько раз на ваш код, и, если я правильно понял, ваши маркировки ваших прямоугольников двумя разными угловыми маркерами. Прошу прощения, если мой ответ - скорее комментарий, чтобы прояснить вашу позицию, а затем действительно ответить.
Ответ-часть::
Если вы ищете подходящий алгоритм, рассмотрите алгоритм сканирования. Я нашел пример здесь @SO для "самого большого прямоугольного решения".
Мой вопрос к вам: что вы действительно ищете?
- лучший способ решить дилемму for-loop
- лучший язык для вашего алгоритма
- более быстрый алгоритм для поиска прямоугольников
Я также должен указать, что Пол и ваше решение дают разные результаты, потому что Паулс предполагает, что углы отмечены одними и теми же значениями, и вы предполагаете, что углы отмечены двумя разными значениями!
Я потратил время и свободу, чтобы проиллюстрировать это с уродливым c & p script:
Он сравнивает оба алгоритма, создавая 2D-поле и заполняя его
string.lowercase и поворачивает углы в верхние регистры.
from random import choice
from string import lowercase
from collections import defaultdict
from itertools import permutations
from copy import deepcopy
m,n = 20, 20
myarray = [[choice(lowercase) for x in xrange(m)] for y in xrange(n)]
def markcorners(i,j,i2,j2):
myarray[i][j] = myarray[i][j].upper()
myarray[i2][j] = myarray[i2][j].upper()
myarray[i2][j2] = myarray[i2][j2].upper()
myarray[i][j2] = myarray[i][j2].upper()
def printrect():
for row in myarray:
print ''.join(row)
print '*'*m
def paul_algo():
tally = defaultdict(list)
for i,row in enumerate(myarray):
for j,n in enumerate(row):
tally[n].append((i,j))
# look for rectangular quads in each list
for k,v in tally.items():
for quad in permutations(v,4):
# sort quad so that we can get rectangle corners
quad = sorted(quad)
(i1,j1),(i2,j2) = quad[0], quad[-1]
# slice out opposite corners to see if we have a rectangle
others = quad[1:3]
if [(i1,j2),(i2,j1)] == others:
markcorners(i1,j1,i2,j2)
def xavier_algo():
for i in xrange(m):
for j in xrange(n):
for i2 in xrange(i + 1, m):
for j2 in xrange(j + 1, n):
if myarray[i][j] == myarray[i2][j2] and myarray[i2][j] == myarray[i][j2]:
markcorners(i,j,i2,j2)
savearray = deepcopy(myarray)
printrect()
xavier_algo()
printrect()
myarray = deepcopy(savearray)
paul_algo()
printrect()