Scala es un lenguaje funcional y orientado a objetos compatible con la máquina virtual de Java. Wiki En esta publicación, no pretendo hacer un curso intensivo de Scala, si no una serie de ejemplos comparados que no muestren las posibilidades de este lenguaje y de la programación funcional. Si después de leer el articulo os pica la curiosidad aquí tenéis un libro de referencia: Scala.
Pues empecemos. Para probar los siguientes ejemplos puedes emplear el siguiente editor online para Scala https://paiza.io/es/projects/new
Todo en Scala es un objeto, eso significa que los elementos del lenguaje todos tienen propiedades implícitas. Como vemos en el primer ejemplo podemos realizar operaciones matemáticas básicas empleando los operadores de toda la vida o podemos usar los operadores funcionales.
En programación clásica para sumar 2 números emplearíamos el operador suma +.
1 2 |
var x = 5 var tradicional = 1+(2*(3/(x))) |
En programación funcional aprovechamos los operadores implícitos de Scala, que van precedidos del punto.
1 |
var funcional = 1.+(2.*(3./(x))) |
A continuación, el código completo.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
object Main extends App{ var x = 5 var tradicional = 1+(2*(3/(x))) var funcional = 1.+(2.*(3./(x))) println("Operación tradicional :( "+ tradicional) println("Operación funcional :) "+ funcional) } |
Si bien, en código tan básico no supone una ventaja radical como veremos más adelante supone una simplificación inmensa del código. Otras de las características de Scala es la asignación perezosa de tipos, es decir es el compilador el que le asigna el tipo a la variable en base a su contenido. Este tipo de variables dinámicas son : Int , Long , Float, Double, Char, String, Boolean, Null, Unit, Nothing, Any, AnyRef.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
object Main extends App{ var x = 5 x=x.+(3) println("Variable tipo entera definida al asignar: "+ x) var s="Hola holita"; println("Variable tipo cadena definida al asignar: "+ s) var moneda: Double = 1.3 println("Variable declarada explícitamente: "+ moneda) } |
Estructuras Básicas de datos y operaciones
La estructura básica para contener datos es el array. Este puede contener un solo tipo de datos, puede tener duplicados y son modificables. En el siguiente ejemplo inicializamos un array de numeros enteros y lo mostramos por consola mediante una función anonima “foreach”.
1 2 3 4 5 6 7 8 9 10 11 |
object Main extends App{ //Arrays reservan el orden de entrada, tienen, duplicados y se puede modificar val numbers = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Recorrido natural:") numbers.foreach((i: Int) => print(" "+ i)) } |
Recorridos natural, funcional y comprehesion con operaciones
Dentro de las herramientas para recorrer conjuntos de datos dentro de escala podemos optar por
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
object Main extends App{ //Suma mediante recorrido val numbers = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) var total =0 numbers.foreach(total += _) println("\nSuma total anónima con recorrido: "+total) var suma = numbers.reduceLeft((a:Int, b:Int) => a + b) println("Suma total con función de objeto: "+suma) println("\nSuma total por comprehesion") var acumulado=0 for (num <- numbers){ acumulado+=num; } print("\t"+acumulado) } |
Filtros sobre datos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
object Main extends App{ //Suma mediante recorrido natural val numbers = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Recorrido filtro y recorrido natural") var result =numbers.filter((i: Int) => i % 2 == 0) result.foreach((i: Int) => print(" "+ i)) println("\nRecorrido filtro y recorrido funcional") numbers.filter((i: Int) => i % 2 == 0).foreach((i: Int) => print(" "+i)) println("\nRecorrido filtro y recorrido por comprehesion") for (num <- numbers.filter((i: Int) => i % 2 == 0)) print("\t"+num) } |
Listas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
object Main extends App{ //Listas // Preservan el orden, pueden contener duplicados y son inmutables val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Recorrido natural:") numbers.foreach((i: Int) => print(" "+ i)) println("\nRecorrido filtro y recorrido funcional") numbers.filter((i: Int) => i % 2 == 0).foreach((i: Int) => print(" "+i)) } |
Conjuntos sets
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
object Main extends App{ //Sets // No preservan el orden, no pueden contener duplicados val numbers = Set(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Recorrido natural:") numbers.foreach((i: Int) => print(" "+ i)) println("\nRecorrido filtro y recorrido funcional") numbers.filter((i: Int) => i % 2 == 0).foreach((i: Int) => print(" "+i)) } |
Tuplas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
object Main extends App{ //Tuples Agrupar valores de diferente tipo val antonio = ("Antonio",37, 10) //Acceso a los campos println("Nombre: "+antonio._1+" Edad: "+antonio._2+" Calificación:"+antonio._3) def abel = ("Abel",27, 5) val (nombre,edad,calificacion)= abel println("Nombre: "+ nombre + "Edad: "+edad+"Calificación:"+calificacion) //Acceso por iterador antonio.productIterator.foreach{ i =>println("Campo = " + i )} //Conversión con funcion propia println("Conversión a String: " + antonio.toString()) //Lista de tuplas val alumnos = List(("Antonio",37, 10),("Abel",27, 5)) alumnos.foreach{ alumno => val (nombre, edad, calificacion) = alumno println(nombre+" "+edad+" "+calificacion) } } |
Maps
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import scala.collection.mutable object Main extends App{ // Maps permite almacenar datos clave->valor val alumnos = Map("Antonio" -> "37", "Abel" -> "27") for ((nombre,nota) <- alumnos) printf("Nombre: %s, Nota: %s\n", nombre,nota) // crear mapa vacio var estudiantes = scala.collection.mutable.Map[String, String]() // crear mapa con valores iniciales var aprendices = scala.collection.mutable.Map("Antonio" ->"Excelente", "Abel" -> "Suspenso") println("Mapa creado e inicializado") for ((nombre,nota) <- alumnos) printf("Nombre: %s, Nota: %s\n",nombre, nota) println("Agregar a Gloria y Ana") // agregar elementos += aprendices += ("Gloria" -> "Bien") aprendices += ("Ana" -> "Bien", "Juan" -> "Aprobado") for ((nombre,nota) <- aprendices) printf("Nombre: %s, Nota: %s\n",nombre, nota) // quitar elementos -= aprendices -= "Abel" aprendices -= ("Ana", "Gloria") println("Quitar Abel, Ana y Gloria") for ((nombre,nota) <- aprendices) printf("Nombre: %s, Nota: %s\n", nombre, nota) // Actualizar elementos aprendices("Antonio") = "Matrícula de honor" println("Actualizar Antonio") for ((nombre,nota) <- aprendices) printf("Nombre: %s, Nota: %s\n", nombre, nota) } |
Combinación de funciones
Map, Foreach, filter, zip, groupby, partition, find, drop & dropWhile, foldLeft, foldRigth, flatten, flatMap, sliding
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") val producto=numbers.map((i: Int) => i*2) producto.foreach((i: Int) => print(" "+ i)) println("\nFiltro, operacion y mostrar por pantalla") numbers.filter((i: Int) => i % 2 == 0).map((i: Int) =>i*2).foreach((i: Int) => print(" "+ i)) } |
Zip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import scala.collection.mutable object Main extends App{ val numbersA = List(1, 2, 3, 4, 5) val lettersB = List("a", "b", "c", "d", "e") println("Operacion y mostrar por pantalla indexado") numbersA.zip(lettersB).zipWithIndex.foreach ( d=>println(s"Clave:"+d._2+" Valor: "+ d._1)) println("Operacion y mostrar por pantalla sin indice") numbersA.zip(lettersB).foreach { num => val (clave,valor)= num println("Clave:"+clave+" Valor: "+ valor) } println("\nFiltro, operacion y mostrar por pantalla") numbersA.filter((i: Int) => i % 2 == 0).zip(lettersB).foreach { num => val (clave,valor)= num println("Clave:"+clave+" Valor: "+ valor) } } |
Partition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") val (a,b)=numbers.partition(_ % 2 == 0) println("Lista de pares") a.foreach((i: Int) => print(" "+ i)) println("\nLista de impares") b.foreach((i: Int) => print(" "+ i)) } |
Groupby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") val grupos=numbers.groupBy(_ % 2 == 0) println("Lista de pares") grupos(true).foreach((i: Int) => print(" "+ i)) println("\nLista de impares") grupos(false).foreach((i: Int) => print(" "+ i)) } |
Find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") val num=numbers.find((i: Int) => i == 5) println("Encontrado "+num) println("Encontrado "+numbers.find((i: Int) => i > 5)) } |
Drop y dropWhile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") println(numbers.drop(5).toString) println(numbers.toString()) println(numbers.dropWhile(_%2==0).toString) println(numbers.toString()) println(numbers.dropWhile(_%2!=0).toString) println(numbers.toString()) } |
FoldLeft y foldRigth
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import scala.collection.mutable object Main extends App{ val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) println("Operacion y mostrar por pantalla") println("FoldLeft") numbers.foldLeft(0) { (m: Int, n: Int) => println("m: " + m + " n: " +n); m + n } println(numbers.foldLeft(0)((m: Int, n: Int) => m + n)) println("FoldRight") numbers.foldRight(0) { (m: Int, n: Int) => println("m: " + m + " n: "+ n); m + n } println(numbers.foldRight(0)((m: Int, n: Int) => m + n)) } |
Flatten
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import scala.collection.mutable object Main extends App{ val numbers = List(List(1, 2, 3, 4, 5) ,List(1, 2, 3, 4, 5)) val union = numbers.flatten println("Operacion y mostrar por pantalla") union.foreach((i: Int)=> print(" "+i)) val couples = List(List("Abel", "suspenso"), List("Antonio","sobresaliente")) val people = couples.flatten println("\n"+people.toString) val peopleOrder = couples.flatten.map(_.capitalize).sorted println("\n"+peopleOrder.toString) val misAmigos = List("Marina", "Andrea", "Paula") val abelAmigos = List("Bin Laden", "Hitler","Calamardo") val gloriaAmigos = List("Bob Esponja", "Paula", "Patricio") val amigosDeAmigos = List(abelAmigos, gloriaAmigos) val amigosDeAmigosFiltrados = amigosDeAmigos.flatten.distinct println("\n"+amigosDeAmigosFiltrados.toString) } |
FlatMap
1 2 3 4 5 6 7 8 9 10 11 |
import scala.collection.mutable object Main extends App{ val numbers = List(List(1, 2, 3, 4, 5) ,List(1, 2, 3, 4, 5)) println(numbers.flatMap(x => x.map(_ * 2))) numbers.flatMap(x => x.map(_ * 2)).filter((i: Int) => i % 2 ==0).foreach((i: Int) => print(" "+ i)) } |
Funciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import scala.collection.mutable object Main extends App{ def addInt( a:Int, b:Int ) : Int = { var sum:Int = 0 sum = a + b return sum } println( "Suma : " + addInt(5,7) ) } |
Clases
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import scala.collection.mutable object Main extends App{ class Alumno(nom: String, not: Int) { var nombre: String = nom var nota: Int = not override def toString(): String = "Alumno: " + nombre + ", " + nota + ""; } val antonio = new Alumno("Antonio", 10) println(antonio) val abel = new Alumno("Abel", 1) println(abel) val gloria = new Alumno("Gloria", 7) val alumnos = antonio :: abel :: gloria :: Nil alumnos.foreach((a: Alumno) => println(" "+ a)) println("Ordenados por nota ascendente: " + alumnos.sortBy(_.nota)) println("Ordenados por nota descendente: " + alumnos.sortBy(-_.nota)) } |
Bibliografía
https://paiza.io/projects
http://www.scala-lang.org/docu/files/ScalaTutorial-es_ES.pdf
https://www.tutorialspoint.com/scala/scala_data_types.htm
https://docs.scala-lang.org/es/tutorials/scala-for-java-programmers.html
http://docs.scala-lang.org/cheatsheets/index.html
https://twitter.github.io/scala_school/collections.html
http://www.codecommit.com/blog/scala/quick-explanation-of-scalas-syntax
https://alvinalexander.com/scala/scala-tuple-examples-syntax
https://alvinalexander.com/scala/create-iterating-scala-string-maps
https://alvinalexander.com/scala/iterating-scala-lists-foreach-for-comprehension
http://allaboutscala.com/tutorials/chapter-2-learning-basics-scala-programming/scalatutorial-learn-use-for-comprehension/
https://www.tutorialspoint.com/scala/scala_tuples.htm
https://www.artima.com/forums/flat.jsp?forum=283&thread=243570
https://alvinalexander.com/scala/how-to-split-sequences-subsets-groupby-partitionscala-cookbook
https://alvinalexander.com/scala/scala-for-loops-foreach-how-to-translated-by-compiler
https://alvinalexander.com/scala/examples-scala-sequences-collection-methods-seq-listarray-buffer
https://alvinalexander.com/scala/how-create-scala-list-range-fill-tabulate-constructors