Básicamente, existen dos tipos de bucles:
Ambos son posibles en Julia, aunque el segundo puede ser más común.
while
Para problemas abiertos, en los que no se sabe de antemano cuántas veces se repetirá el bucle, Julia tiene el bucle while.
La forma básica es bastante sencilla:
while condition
do_something()
end
En este caso, el programa seguirá dando vueltas al bucle hasta que condition deje de ser true.
Hay dos formas de salir del bucle antes de tiempo:
break hace que el bucle termine, y la ejecución continúa en la siguiente línea después del end del bucle.return x detiene la ejecución de la función actual y le devuelve el valor x a quien la llamó.Con estas opciones disponibles, a veces puede ser conveniente crear un bucle «infinito» con while true ... end y confiar en encontrar una condición de parada dentro del cuerpo del bucle que active un break o un return.
La ilustración más sencilla es recorrer un rango.
Si queremos hacer algo 10 veces:
for n in 1:10
do_something(n)
end
Si la iteración actual no cumple alguna condición, es posible saltar de inmediato a la siguiente iteración con un continue:
for n in 1:10
if is_useless(n)
continue
end
# we decided this iteration could be useful
do_something_slow(n)
end
En una forma más corta, el bloque if podría reemplazarse por is_useless(n) && continue.
Se puede recorrer muchos otros tipos de colecciones: los elementos de un array, los caracteres de un string, las claves de un diccionario...
El requisito es que la colección debe ser iterable.
Esto se explicará con más detalle en un concepto posterior, pero, en esencia, la colección debe tener una forma de entregar el siguiente elemento cuando se le pida, además de una forma de indicar que se llegó al final y que no hay más elementos.
Los ejemplos hasta ahora recorren el rango 1:10, donde el valor es también el índice del bucle.
En general, puede que se necesite el índice y no solo el valor.
Para esto se usa la función eachindex(), por ejemplo for i in eachindex(my_array) ... end.
Escribir bucles explícitos tiende a ser menos común en Julia que en muchos lenguajes tradicionales, ya que hay varias opciones más concisas.
Una situación particularmente común es cuando necesitamos construir un vector nuevo a partir de los elementos de alguna otra colección (vector, string, conjunto... hay muchas posibilidades).
A quienes les gustan las comprensiones de listas en Python les alegrará saber que Julia puede usar una sintaxis similar.
La esencia de esto es armar un bucle muy compacto dentro de un vector.
La sintaxis más sencilla tiene la forma result = [f(x) for x in some_collection].
Con un bucle tradicional, eso podría escribirse así:
result = []
for x in some_collection
push!(result, f(x))
end
De forma opcional, se puede agregar un condicional al final para seleccionar solo los elementos de la colección que cumplan la condición:
# multiples of 3
julia> [n^2 for n in 1:10 if n%3 == 0]
3-element Vector{Int64}:
9
36
81
# letters beyond 'h' in the alphabet
julia> [uppercase(c) for c in "Julia" if c > 'h']
3-element Vector{Char}:
'U': ASCII/Unicode U+0055 (category Lu: Letter, uppercase)
'L': ASCII/Unicode U+004C (category Lu: Letter, uppercase)
'I': ASCII/Unicode U+0049 (category Lu: Letter, uppercase)
La sintaxis es similar a la de Python, pero no idéntica. Hay algunas diferencias para varias variables o para arrays multidimensionales, así que este tema se cubrirá con más detalle en un concepto posterior.
Como lenguaje moderno y en gran medida funcional, Julia (por supuesto) tiene varias formas de operar sobre colecciones, no solo un bucle explícito o un bucle compacto dentro de una comprensión.
En conceptos posteriores veremos alternativas como broadcasting y funciones de orden superior.