Cuando trabajamos con colecciones en Scala, una de las formas más directas de iterar sobre sus elementos es utilizando la operación foreach. Esta operación nos permite ejecutar una función para cada elemento de la colección, pasando ese elemento como parámetro a la función. Por ejemplo, si tenemos una lista de lenguajes de programación, podemos imprimir un mensaje para cada uno usando foreach de esta manera:
val lenguajes = List("Java", "Scala", "Python")
lenguajes.foreach { l =>
println(s"$l me parece un buen lenguaje")
}
Aquí, la función que pasamos a foreach recibe cada lenguaje l y ejecuta el código dentro del bloque para cada uno. Es importante destacar que foreach devuelve Unit, es decir, no produce un nuevo valor ni transforma la colección, simplemente ejecuta efectos secundarios como imprimir en pantalla. Por eso, si queremos transformar una colección en otra, debemos usar operaciones como map o flatMap.
Además de foreach, Scala nos ofrece la palabra clave for, que nos permite escribir bucles de forma más concisa y expresiva. Un bucle for básico para iterar sobre la lista de lenguajes sería:
for (l <- lenguajes) {
println(s"$l me parece un buen lenguaje")
}
Este código es equivalente al anterior con foreach, pero resulta más compacto y legible. La sintaxis l <- lenguajes indica que para cada elemento l en la colección lenguajes se ejecuta el bloque de código.
Una de las grandes ventajas del for en Scala es que podemos combinar múltiples colecciones para generar productos cartesianos de sus elementos. Por ejemplo, si tenemos otra lista con opiniones sobre los lenguajes, podemos combinarlas así:
val opiniones = List("conciso", "moderno", "antiguo")
for {
l <- lenguajes
o <- opiniones
} {
println(s"El lenguaje $l me parece $o")
}
Este bucle anidado recorre cada lenguaje y para cada uno recorre todas las opiniones, generando todas las combinaciones posibles. El resultado es una serie de frases que expresan cada opinión para cada lenguaje.
También podemos aplicar filtros dentro del for para iterar solo sobre elementos que cumplan ciertas condiciones. Por ejemplo, si queremos considerar solo los lenguajes que terminan con la letra a y las opiniones que empiezan con a, podemos escribir:
for {
l <- lenguajes if l.endsWith("a")
o <- opiniones if o.startsWith("a")
} {
println(s"El lenguaje $l me parece $o")
}
Este código solo imprimirá combinaciones donde el lenguaje termine en a y la opinión comience con a. Así, el for nos permite filtrar elementos de forma muy natural y legible.
Aunque podríamos lograr resultados similares usando combinaciones de filter y foreach, la sintaxis del for suele ser más clara y concisa. Por ejemplo, hacer lo mismo con operaciones encadenadas sería más verboso y menos intuitivo:
lenguajes.filter(_.endsWith("a")).foreach { l =>
opiniones.filter(_.startsWith("a")).foreach { o =>
println(s"El lenguaje $l me parece $o")
}
}
Aunque funcional, este código es más largo y menos fácil de leer que la versión con for.
En definitiva, foreach es útil para ejecutar código sobre cada elemento de una colección cuando no necesitamos transformar los datos, mientras que la palabra clave for nos ofrece una forma más poderosa y expresiva de iterar, combinar y filtrar colecciones con una sintaxis más limpia y concisa. Esto facilita escribir código más sencillo de comprender y mantener, especialmente cuando trabajamos con múltiples colecciones y condiciones.