TransWikia.com

Como detener un bucle for sin usar un break?

Stack Overflow en español Asked by Julián Taborda on December 20, 2020

mi problema es el siguiente, tengo una lista de números de los cuales debo encontrar uno usando búsqueda lineal, pero lo que sucede es que cuando encuentro dos números repetidos en la lista la iteración debe detenerse SIN USAR BREAK, este es el código:

p = [2, 10, 23, 23, 41, 45, 57, 90]
num = 23

t = bool(False)
print('nNumber:',num) 
    

for z in range(0,len(p)):
    if p[z]==num: 
        for i in range(z+1):
             print('nIteration:',i,',L[',i,']','=',p[i])
             i+=1
        
        print('nNumber found in the position:',z)
        t = True
    

if t == True: 
    print('nAmount of Iterations:',i) 
else: 
    print('nNumber no found, try again')

2 Answers

Hay dos requisitos un tanto chocantes en la pregunta:

  • No usar break. ¿Por qué? Es una instrucción perfectamente válida y de hecho la única que tiene sentido usar en este contexto (otras soluciones son increíblemente complicadas como veremos)
  • Usar for ¿por qué? No es la estructura de control apropiada cuando quieres iterar solo hasta que se cumpla una cierta condición. En Python el for de hecho no es una estructura de control convencional, es un iterador, y permanecerá iterando hasta que el iterable se agote. La estructura de control natural para bucles interrumpibles es while.

Problema de ejemplo

Vamos a generar números de 0 a 1000, pero dentro del bucle queremos parar cuando el número alcance el valor 5.

Usando while

En este caso no generamos números con un generador, sino que tenemos una variabl que vamos incrementando:

i = 0
while i<5:
   print(i)
   i = i+1

Si quieres, también puedes hacer uso de una variable booleana que te diga cuándo parar de iterar:

i = 0
seguir = True
while seguir:
   print(i)
   i = i + 1
   if i==5:
      seguir = False

Usando for y break

for i in range(1000):
  print(i)
  if i == 5:
     break

Aunque el iterador range(1000) no se agota hasta haber generado los 1000 elementos, sin embargo rompemos el bucle cuando sólo ha generado 5.

¡Mira mamá! ¡sin break!

Si no usas break sólo hay una forma de hacer que for deje de iterar, y es que el iterable sobre el cual estaba iterando se agote.

Un iterable como range(1000) no se agotará hasta haber generado 1000 números. Pero podemos crear una función generadora que retorne antes de haber generado 1000, y que podamos controlar con una variable booleana externa. Por ejemplo así:

seguir = True
def range_con_stop(n):
  for i in range(n):
    if seguir==False:
      return
    yield i

Esta funcíón es similar a range(). En cada iteración devuelve un número más (en el yield), pero si seguir se hace False, el generador terminará. Esto podemos aprovecharlo para implementar el bucle for buscado así:

for i in range_con_stop(1000):
  print(i)
  if i==5:
    seguir = False

Otro enfoque, más retorcido si cabe, es usar una expresión generadora y cerrarla dentro del bucle cuando queramos salir. Así:

generador = (x for x in range(1000))
for i in generador:
   print(i)
   if i==5:
      generador.close()

Correct answer by abulafia on December 20, 2020

Usando for dentro de una función

Como ya sugirieron, puedes poner el for dentro de una función y ejecutar un return en lugar de un break.

En el fondo es la misma cosa, escrita de otra manera.

La función buscar retorna el índice de la primera ocurrencia. Si no hay repetición, devuelve -1.

def buscar(numero, lista):
    for i in range(len(lista)):
        if lista[i:i+2] == [numero, numero]:
            return i  # Encontrado!
    return -1  # No encontrado.

p = [2, 10, 23, 23, 41, 45, 57, 90]
posicion = buscar(23, p)
print(posicion)

Usando excepciones

En lugar de break, levantamos una excepción con raise que nos saca del for.

La variable posicion tiene el indice de la primera ocurrencia, o -1 si no se encontro.

p = [2, 10, 23, 23, 41, 45, 57, 90]
numero = 23
posicion = -1

try:    
    for i in range(len(p)):
        if p[i:i+2] == [numero, numero]:
            posicion = i
            raise StopIteration
except:
    pass

print(posicion)

Answered by Candid Moe on December 20, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP