Итерация по 2d-массиву по расширяющейся круговой спирали

Учитывая n на n матрицу M в строке i и столбце j я хотел бы перебрать все соседние значения по круговой спирали.

Смысл этого состоит в том, чтобы проверить некоторую функцию f , которая зависит от M, чтобы найти радиус вдали от (i, j) , в котором f возвращает Истина .Итак, f выглядит так:

def f(x, y):
    """do stuff with x and y, and return a bool"""

и будет вызываться так:

R = numpy.zeros(M.shape, dtype=numpy.int)
# for (i, j) in M
for (radius, (cx, cy)) in circle_around(i, j):
    if not f(M[i][j], M[cx][cy]):
       R[cx][cy] = radius - 1
       break

Где circle_around - это функция, которая возвращает (итератор) индексы по круговой спирали. Таким образом, для каждой точки в M этот код будет вычислять и сохранять радиус от этой точки, в котором f возвращает True .

Если есть более эффективный способ вычисления R , я бы тоже был открыт для него.


Обновление:

Спасибо всем, кто прислал ответы. Я написал короткую функцию для построения графика вывода ваших итераторов circle_around , чтобы показать, что они делают. Если вы обновите свой ответ или опубликуете новый, вы можете использовать этот код для проверки своего решения.

from matplotlib import pyplot as plt
def plot(g, name):
    plt.axis([-10, 10, -10, 10])
    ax = plt.gca()
    ax.yaxis.grid(color='gray')
    ax.xaxis.grid(color='gray')

    X, Y = [], []
    for i in xrange(100):
        (r, (x, y)) = g.next()
        X.append(x)
        Y.append(y)
        print "%d: radius %d" % (i, r)

    plt.plot(X, Y, 'r-', linewidth=2.0)
    plt.title(name)
    plt.savefig(name + ".png")

Вот результаты: сюжет (circle_around (0, 0), "F.J") : circle_around by F.J

plot (circle_around (0, 0, 10), "WolframH") : circle_around by WolframH

Я закодировал предложение Магния следующим образом:

def circle_around_magnesium(x, y):
    import math
    theta = 0
    dtheta = math.pi / 32.0
    a, b = (0, 1) # are there better params to use here?
    spiral = lambda theta : a + b*theta
    lastX, lastY = (x, y)
    while True:
        r = spiral(theta)
        X = r * math.cos(theta)
        Y = r * math.sin(theta)
        if round(X) != lastX or round(Y) != lastY:
            lastX, lastY = round(X), round(Y)
            yield (r, (lastX, lastY))
        theta += dtheta

plot (circle_around (0, 0, 10), «magnesium») : circle_around by Magnesium

Как видите, ни один из результатов, удовлетворяющих интерфейсу, который я ищу, не дал круговой спирали, охватывающей все индексы около 0, 0. FJ's является наиболее близким, хотя WolframH попадает в нужные точки. , только не по спирали.

23
задан Jason Sundram 7 March 2012 в 22:03
поделиться