Básicamente, hay dos tipos de bucles:
Ambos son posibles en Julia, aunque el segundo puede que sea más habitual.
while
Para problemas abiertos, en los que no se sabe de antemano cuántas veces se repetirá el bucle, Julia cuenta con 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 se salga del bucle y que la ejecución continúe en la línea siguiente al end del bucle.return x detiene la ejecución de la función actual y pasa el valor devuelto x de vuelta a quien la llamó.Con estas opciones disponibles, a veces puede resultar cómodo 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.
El ejemplo más sencillo 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 inmediatamente 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 sustituirse por is_useless(n) && continue.
Se pueden 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 sea iterable.
Esto se explicará con más detalle en un concepto posterior, pero, en esencia, la colección debe tener alguna forma de proporcionar el siguiente elemento cuando se le pida, además de una forma de indicar que se ha llegado al final y que no hay más elementos.
Los ejemplos anteriores 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 eso se usa la función eachindex(), por ejemplo, for i in eachindex(my_array) ... end.
Escribir bucles explícitos suele ser menos habitual en Julia que en muchos lenguajes tradicionales, porque hay varias opciones más concisas.
Una situación especialmente habitual es cuando necesitamos construir un nuevo vector a partir de los elementos de otra colección (vector, string, conjunto... hay muchas posibilidades).
A quien le gusten las comprensiones de listas en Python le alegrará saber que Julia puede usar una sintaxis similar.
La esencia de esto es crear 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 añadir 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 arrays multidimensionales, así que este tema se tratará con más detalle en un concepto posterior.
Como lenguaje moderno y en gran medida funcional, Julia tiene (por supuesto) diversas formas de operar con colecciones, no solo un bucle explícito o un bucle compacto dentro de una comprensión.
En conceptos posteriores veremos alternativas como el broadcasting y las funciones de orden superior.