2010-12-31 14 views
5

Necesito buscar un artículo en una lista alrededor de un índice dado dentro de un radio dado. Actualmente utilizo esta función para generar la alternancia compensaciones para la búsqueda:¿Cómo generar un rango alterno?

def generateSearchIndizes(radius): 
    for i in range(1, radius + 1): 
     yield i 
     yield -i 

El código que hace la búsqueda se ve algo como esto:

for i in generateSearchIndizes(): 
    if pred(myList[baseIndex + i]): 
     result = myList[baseIndex + i] 
     break # terminate search when first item is found 

Mi pregunta es, ¿hay una forma más elegante para generar la búsqueda indiza, ¿quizás sin definir una función especial?

+0

Ok, esto es solo un ejemplo, y uno estúpido en eso. Lo he corregido –

Respuesta

4

hay una manera más elegante para generar los índices de búsqueda

No creo que hay una manera más elegante. Tu código es muy simple y claro.

¿quizás no tiene que definir una función especial?

Sí, eso es definitivamente posible.

>>> [b for a in ((x,-x) for x in range(1, 10 + 1)) for b in a] 
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10] 
+2

Ok, me quedaré con la función separada, es mucho más legible. –

0

¿Quizás una expresión de generador?

for i in (x/2 * (x%2 * 2 - 1) for x in xrange(2, radius*2)): 
    print i 

Es corto y se adapta a su "sin definir una función especial" requisito ...

Pero, franky, todavía prefiere usar esa función especial en lugar - por el simple hecho de tener un código más claro. :)

1

Aquí es mi ir en él:

from itertools import chain 

>>> list(chain(*zip(range(1, 7), range(-7, 0)[::-1]))) 
[1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6] 

los ajustes necesarios.:)

0

¿Por qué no hacerlo con un bucle interno, en lugar de crear un generador de cobarde:

found = False 
for i_abs in range(1, radius+1): 
    for i in (i_abs, -i_abs): 
     listitem = myList[baseIndex + i] 
     if pred(listitem): 
      result = listitem 
      found = True 
      break # terminate search when first item is found 
    if found: 
     break 
else: 
    # handling in case no match found for pred 

Algunos otros comentarios:

  • nunca probar el elemento de orden 0

  • ya que está probando desde ambos izquierda y derecha, debe detenerse después de i_abs alcanza la mitad marca

  • No me gusta repetir las operaciones de indexación de listas, preferiría repetir una referencia de variable; así que levanté los repetidos myList[baseIndex+i] y asignado a listitem

  • debe añadir un poco de manejo en caso de no hay ningún elemento coincidente encontró

  • en lugar de romper el bucle interno (que aquí requiere un extra found variable para romper el ciclo for exterior), que podría ser mejor que acaban de volver result derecha desde el bucle interno ,

como en:

for i_abs in range(1, radius+1): 
    for i in (i_abs, -i_abs): 
     listitem = myList[baseIndex + i] 
     if pred(listitem): 
      return listitem 

entonces no hay gestión de descanso o found variable requerida.

0

¿Por qué alternar -i, i? Sólo hacer:

for i in range(-radius, radius+1): 
    listitem = myList[baseIndex + i] 
     if pred(listitem): 
      return listitem 

O si es absolutamente necesario abordar desde el frente y la parte posterior para conseguir la más externa pred-matcher, ¿qué tal:

for i in sorted(range(-radius, radius+1), key=abs): 
    listitem = myList[baseIndex + i] 
     if pred(listitem): 
      return listitem 

Si usted tiene que hacer esto a menudo, acaba de construir sorted(range(-radius,radius+1),key=abs) vez y manténlo para futuras iteraciones.

Si no debe utilizar el elemento 0 ', simplemente inserte un if not i: continue al comienzo de su ciclo.

+0

'ordenado (rango (-radio, radio + 1), clave = abs) [1:]' eliminaría el elemento zeroth. – martineau

0

Esto me parece al menos tan legible como una función separada - y posiblemente más comprensible:

radius = 3 
for outerbounds in ((-r,r) for r in range(1,radius+1)): 
    for i in outerbounds : 
     print i 
# -1 
# 1 
# -2 
# 2 
# -3 
# 3 
0

su propia solución, la adición de un yield 0 al comienzo del generador, es el más sencillo (también conocido como pitónico).

Aquí es un generador de desplazamiento infinita con un algoritmo diferente:

def gen_offsets(): 
    offset= 0 
    yield offset 
    step= 1; sign= 1 
    while 1: 
     offset+= sign*step 
     yield offset 
     step+= 1; sign= -sign 

Una forma más extravagante (también conocido como no-tan-Pythonic :) escribir el algoritmo anterior es:

import itertools as it, operator as op 

def gen_offsets(): 
    steps= it.imap(op.mul, it.count(1), it.cycle((1, -1))) 
    offset= 0 
    yield offset 
    for step in steps: 
     offset+= step 
     yield offset 
Cuestiones relacionadas