Iraterate sobre una matriz 2D en una espiral circular en expansión

Dan ann porn matrizM, en la filai y columnaj, Me gustaría iterar sobre todos los valores vecinos en una espiral circular.

El punto de hacer esto es probar alguna función,f, que depende de M, para encontrar el radio alejado de(i, j) en el cualf devolucionesTrue. Entonces,f Se ve como esto

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

y se llamaría así:

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

Dóndecircle_around es la función que devuelve (un iterador a) índices en una espiral circular. Entonces, para cada punto enM, este código calcularía y almacenaría el radio desde ese punto en el quef devolucionesTrue.

Si hay una manera más eficiente de computarR, Yo también estaría abierto a eso.

Actualizar

Gracias a todos los que enviaron respuestas. He escrito una función corta para trazar la salida de tucircle_around iteradores, para mostrar lo que hacen. Si actualiza su respuesta o publica una nueva, puede usar este código para validar su solución.

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

Aquí están los resultados:plot(circle_around(0, 0), "F.J"):

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

He codificado la sugerencia de Magnesium de la siguiente manera:

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"):

omo puede ver, ninguno de los resultados que satisfacen la interfaz que estoy buscando ha producido una espiral circular que cubre todos los índices alrededor de 0, 0. FJ es el más cercano, aunque WolframH alcanza los puntos correctos, solo no en orden espiral.

Respuestas a la pregunta(14)

Su respuesta a la pregunta