Scala Code Snippets: Functional Programming and OOP
Scala Code Snippets: Functional and Object-Oriented Programming
Functional Programming Examples
Counting Equal Pairs with Tail Recursion
The cuentaIgualesTail
function calculates the number of pairs in a list where the first element of the pair, when passed through a function f
, is equal to the second element. It uses tail recursion for efficiency.
def cuentaIgualesTail(listaTuplas: List[(Int,Int)], f: (Int)=> Int) : Int = { cuentaIgualesTailAux(listaTuplas,f,0) }; def cuentaIgualesTailAux(listaTuplas: List[(Int,Int)], f: (Int)=> Int, Res: Int) : Int = { if(listaTuplas.isEmpty) Res else if(f(listaTuplas.head._1) == listaTuplas.head._2) { cuentaIgualesTailAux(listaTuplas.tail,f,(1 + Res)) } else cuentaIgualesTailAux(listaTuplas.tail,f,Res) };
Counting Equal Pairs with Higher-Order Functions
These functions demonstrate different ways to achieve the same result using higher-order functions like count
and filter
.
def CuentaIgualesFUNC(x:(Int,Int),f: Int=>Int): Boolean = { f(x._1) == x._2 } def cuentaIgualesFOS(listaTuplas: List[(Int,Int)], f: (Int)=> Int): Int = { listaTuplas.count(CuentaIgualesFUNC(_,f)) }; def cuentaIgualesFOSTUPLA(listaTuplas: List[(Int,Int)], f: (Int)=> Int): List[(Int,Int)] = { listaTuplas.filter(CuentaIgualesFUNC(_,f)) }; def cuentaIgualesFOS1(lista: List[(Int,Int)], f:(Int)=>(Int)) : Int = { lista.count((x: (Int,Int)) => f(x._1) == x._2) };
Generating Pairs of Numbers
The parejasNums
function generates a list of all possible pairs of numbers from 0 up to a given integer x
.
def parejasNums(x: Int) = { (for(x1 <- 0 to x; y1 <- 0 to x) yield(x1,y1)).toArray.toList };
Object-Oriented Programming Examples
Basic Integer Queue
This demonstrates a simple queue implementation using a trait and a class.
abstract class IntQueue { def put(x:Int): Unit } class BasicIntQueue extends IntQueue { private val buf = new ListBuffer[Int] def put(x: Int) = buf += x };
Trait for Doubling Values
The GetDouble
trait modifies the put
method to double the input value before adding it to the queue.
trait GetDouble extends IntQueue { abstract override def put(x: Int) = super.put(2 * x) } class MiCola extends BasicIntQueue with GetDouble;
Searching for a Word
The BuscaPalabra
function searches for a word within a string and returns its index.
def BuscaPalabra(Palabra: String, Palabras: String) : Int ={ val aux = Palabras.split(" ") aux.indexOf(Palabra) };
Ternary Tree
This section defines a ternary tree data structure with methods for summing node values and managing the total number of trees created.
abstract class TernaryTree{ def sumaNodos(): Int } object Vacio extends TernaryTree{ def sumaNodos(): Int = 0 } class NodoTernaryTree (val value: Int, val left: TernaryTree, val mid: TernaryTree, val right: TernaryTree) extends TernaryTree{ def sumaNodos(): Int ={ value + left.sumaNodos() + mid.sumaNodos() + right.sumaNodos() }; } class NodoTernaryTree private(val value: Int, val left: TernaryTree, val mid: TernaryTree, val right: TernaryTree) extends TernaryTree{ NodoTernaryTree.inc() override def sumaNodos(): Int ={ value + left.sumaNodos() + mid.sumaNodos() + right.sumaNodos() } } object NodoTernaryTree{ private var totalTrees = 0 def numTotalTrees() = totalTrees private def inc() = totalTrees = totalTrees+1 def apply(value: Int, left: TernaryTree, mid: TernaryTree, right: TernaryTree)={ new NodoTernaryTree(value,left,mid,right) } }
Generic Tree
This defines a generic tree data structure with methods for counting nodes, finding elements, summing node values, calculating height, finding the maximum value, getting nodes at a specific level, and filtering nodes based on a predicate.
class TreeT[T](dato:T, listaHijos:List[TreeT[T]]){ var d:T = dato var lh:List[TreeT[T]] = listaHijos def this(dato:T) ={ this(dato, Nil) } def numNodos():Int = { if(lh.isEmpty) 1 else lh.map(_.numNodos).foldRight(1)(_ + _) } def find(elemento:T, comparar:(T, T) => (Boolean)):Boolean = { if(lh.isEmpty) comparar(elemento, d) else lh.map(_.find(elemento,comparar)).foldRight(comparar(elemento, d))(_ || _) } def sumarNodos(suma:(T, T) => (T)):T = { if(lh.isEmpty) d else lh.map(_.sumarNodos(suma)).foldRight(d)(suma) } def altura():Int = { if(lh.isEmpty) 0 else 1 + lh.map(_.altura).foldRight(0)((a:Int, b:Int) => {if(a > b) a else b}) } def mayor(maximo:(T, T) => (T)):T = { if(lh.isEmpty) d else lh.map(_.mayor(maximo)).foldRight(d)(maximo) } def nodosNivel_i(i:Int):List[T] = { var lista:List[T] = Nil if(i == 1) List(d) else if(lh.isEmpty) List() else lh.map(_.nodosNivel_i(i-1)).foldRight(lista)(_ ::: _) } def filtra(predicado:(T)=>(Boolean)):List[T] = { var lista:List[T] = Nil if(lh.isEmpty) if(predicado(d)) List(d) else List() else if(predicado(d)) d :: lh.map(_.filtra(predicado)).foldRight(lista)(_ ::: _) else lh.map(_.filtra(predicado)).foldRight(lista)(_ ::: _) } }
Binary Tree
This section defines a binary tree with methods for counting nodes and calculating height, using both direct recursion and pattern matching.
abstract class BinaryTree{ def numNodos():Int = 0 def altura():Int = 0 } object Vacio extends BinaryTree; class NodoBinaryTree(val dato:Int, val izq:BinaryTree, val der:BinaryTree) extends BinaryTree{ override def numNodos():Int = { var nodosIzquierda:Int = izq.numNodos() var nodosDerecha:Int = der.numNodos() 1 + nodosIzquierda + nodosDerecha } override def altura(): Int = { 1 + math.max(izq.altura(), der.altura()) } def numNodosMatch(arbol:BinaryTree):Int = { arbol match { case t : NodoBinaryTree => 1 + numNodosMatch(t.izq) + numNodosMatch(t.der) case Vacio => 0 } } def alturaMatch(arbol:BinaryTree):Int = { arbol match{ case t:NodoBinaryTree => 1 + math.max(alturaMatch(t.izq), alturaMatch(t.der)) case Vacio => 0 } } };
Generic Binary Tree
This defines a generic binary tree with a method for summing node values.
class NodoBinaryTree[T](var dato:T, var izq:BinaryTree[T], var der:BinaryTree[T]) extends BinaryTree[T]{ override def numNodos(): Int = { 1 + izq.numNodos() + der.numNodos() } override def altura(): Int = { 1 + math.max(izq.altura(), der.altura()) } def sumarNodos(neutro:T, sumar:(T,T) => T): T = { sumar(dato, sumar(izq.sumarNodos(neutro, sumar), der.sumarNodos(neutro, sumar))) } }
Applying a Function to 3D Coordinates
These functions apply a given function to a specific coordinate (x, y, or z) of a list of 3D points.
def aplica3D(lista: List[(Int,Int,Int)], f: (Int)=>Int, c: String): List[(Int,Int,Int)] = { if(lista.isEmpty) Nil else c match { case "x" => (f(lista.head._1), lista.head._2, lista.head._3) :: aplica3D(lista.tail, f, c) case "y" => (lista.head._1, f(lista.head._2), lista.head._3) :: aplica3D(lista.tail, f, c) case "z" => (lista.head._1, lista.head._2, f(lista.head._3)) :: aplica3D(lista.tail, f, c) } }; def transforma(x: (Int, Int, Int), f: Int => Int, c: String): (Int, Int, Int) = { c match { case "x" => (f(x._1), x._2, x._3) case "y" => (x._1, f(x._2), x._3) case "z" => (x._1, x._2, f(x._3)) } } def aplica3DMap(lista: List[(Int,Int,Int)], f: (Int)=>Int, c: String): List[(Int,Int,Int)] = lista.map((x)=>transforma(x,f,c))
Swapping Pairs
The intercambia
function swaps the elements of each pair in a list.
def intercambia(lista: List[(Int,Int)]): List[(Int,Int)] = lista.map((pareja)=>(pareja._2, pareja._1))
Finding the Minimum Element
These functions find the minimum element in a list based on a provided comparison function.
def minimo[A](lista: List[A], menor: (A,A)=>Boolean) : A = { if (lista.tail.isEmpty) lista.head else { val minResto = minimo(lista.tail, menor) if (menor(lista.head, minResto)) lista.head else minResto } } def minimaTupla[A,B](lista: List[(A,B)], toInt: ((A,B))=>Int): (A,B) = { minimo(lista, (t1:(A,B), t2:(A,B)) => toInt(t1) < toInt(t2)) }
Actor Model Examples
This section demonstrates the use of actors for concurrent programming in Scala.
import scala.actors.Actor import scala.actors.Actor._ class Ping(count: Int, pong: Actor) extends Actor { def act() { for (i <- 1 to count) { println("Ping envĂa Ping") pong ! "Ping" } pong ! "Stop" } } class Pong extends Actor { def act() { var pingCount = 0 loop { react { case "Ping" => println("Pong recibe Ping") pingCount += 1 sender ! "Pong" case "Stop" => println("Pong se para") println("Pong ha recibido " + pingCount + " mensajes Ping") exit() } } } } val pong = new Pong val ping = new Ping(10, pong) ping.start pong.start val intActor = actor { receive { case x: Int => println("Tengo un Int: "+ x) } }
Applying a Function to Pairs in a List
The aplicaFuncionDosArgsList
function applies a two-argument function to each pair in a list.
def aplicaFuncionDosArgsList(lista: List[(Int,Int)], f: (Int,Int) => (Int)): List[Int] ={ if(lista.isEmpty) List() else f(lista.head._1, lista.head._2) :: aplicaFuncionDosArgsList(lista.tail, f) };
Creating an Iterator
The creaIterador
function creates an iterator from a string, processing each word with a given function.
def creaIterador[A](frase: String, base: A, procesaPalabra: (String) => A): () => A = { var listaCadenas = frase.split(" ").toList () => { if (listaCadenas.isEmpty) base else { val cadena = listaCadenas.head listaCadenas = listaCadenas.tail procesaPalabra(cadena) } } }
Parking Meter Simulation
The makeParkimetro
function simulates a parking meter, allowing payment and time tracking.
def makeParkimetro(dinero: Double) : (String,Double) => Any = { var tiempo = dinero/0.01 var auxdinero = dinero def pagarDinero(d:Double) = { tiempo= tiempo + d/0.01 auxdinero = auxdinero + d tiempo } def getTiempo() = { tiempo } def getDinero() = { auxdinero } def decTiempo()={ tiempo=tiempo-1 tiempo } (mens: String, d:Double) => { mens match{ case "pagar" => pagarDinero(d) case "tick" => decTiempo() case "getTiempo" => getTiempo() case "getDinero" => getDinero() case _=> "error" } } }
Coin Toss Simulation
The makeMoneda
function simulates a coin toss, returning”head”,”tail”, or”edg” based on the input value.
def makeMoneda(x: Int): ()=>String = { var valor = x var moneda = 1 () => { valor = valor-1 if(valor == 0){ valor = x "canto" } else if(moneda % 2 != 0){ moneda = moneda + 1 "cara" } else{ moneda = moneda + 1 "cruz" } } };
Counter with Custom Function
The makeContador
function creates a counter that updates its value based on a provided function.
def makeContador(valorInicial: Int, f: (Int) => (Int)): ()=> Int = { var contador = valorInicial ()=>{ contador = f(contador) contador } };
Repeating Code
The repetirVeces
function repeats a given code block a specified number of times.
def repetirVeces (codigo: => Unit) (numVeces: Int) = { for (a <- 1 to numVeces) { codigo } };
Color Class Hierarchy
This defines a Color
class hierarchy with subclasses for Red
, Green
, and Blue
, and a function to print color information.
class Color(val red : Int, val green : Int, val blue: Int) case class Red(r:Int) extends Color(r,0,0) case class Green(g: Int) extends Color (0,g,0) case class Blue(b: Int) extends Color(0,0,b) def printColor(c: Color) = c match { case Red(v) => println("Red: " + v) case Green(v) => println("Green: " + v) case Blue(v) => println("Blue: " + v) case col:Color => { print("R: " + col.red + ", ") print("G: " + col.green + ", ") println("B: " + col.blue) } };
Character Class Hierarchy
This defines a Persona
abstract class with a Mago
subclass, demonstrating inheritance and polymorphism.
abstract class Persona(val nombre: String){ var poder: Int var resistencia:Int var velocidad: Int def Saluda(): String def puntos(): (Int,Int,Int) def aumentaPuntos(tipo: String, puntuacion: Int) }; class Mago(nombre: String) extends Persona(nombre){ var poder = 5 var resistencia = 2 var velocidad = 4 def saludar() = "Hola, soy el mago " + nombre override def Saluda() = saludar() def puntos(): (Int, Int, Int) = (poder,resistencia,velocidad) def setVelocidad(v: Int) = { velocidad=v } def setResistencia(r: Int) ={ resistencia=r } def setPoder(p: Int) = { poder=p } def aumentaPuntos(tipo: String, puntuacion: Int){ tipo match{ case "Velocidad" => setVelocidad(velocidad+puntuacion) case "Poder" => setPoder(poder+puntuacion) case "Resistencia" => setResistencia(resistencia+puntuacion) } } }
Iterator and Implicit Conversion
This defines an Iterador
class and an implicit conversion to enable a more concise syntax for looping.
class Iterador(i: Int) { def hasta(j: Int) (codigo: => Unit) = { for(a <- i to j) { codigo } } } implicit def convierteIterador(i: Int) = new Iterador(i)
Counting Occurrences
The ocurrencias
function counts the number of times an element appears in a list.
def ocurrencias(elemento:String, lista:List[String]) : Int = { if (lista.isEmpty) 0 else if (elemento == lista.head) 1+ocurrencias(elemento, lista.tail) else ocurrencias(elemento, lista.tail) }
2D Point Class
This defines a Punto2D
class with methods for calculating distance and checking equality.
class Punto2D (val x:Double, val y:Double) { def distancia2D(p: Punto2D) : Double = { Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2)) } override def equals(other: Any): Boolean = other match { case that: Punto2D => (this.x == that.x) && (this.y == that.y) case _ => false } }
Geometric Figure Abstract Class
This defines an abstract class Figura
with methods for calculating area and checking intersection.
abstract class Figura { def area() : Double def intersectaMismoTipo(otra: Figura) : Boolean }
Tree with Higher-Order Functions
This defines a TreeFOS
class with methods for converting to a list, summing node values, and counting nodes.
class TreeFOS(val dato: Int, hijos: List[TreeFOS]) { def this(dato: Int) = this(dato, List()) def toList(): List[Int] = this.dato :: this.hijos.map(_.toList).fold(Nil)(_ ::: _) def sumTotal(): Int = this.dato + this.hijos.map(_.sumTotal).fold(0)(_+_) def numNodos(): Int = 1 + this.hijos.map(_.numNodos).fold(0)(_+_) };
Range Comparator Builder
The construyeComparadorRango
function creates a comparator function that checks if a pair of integers falls within a specified range.
def construyeComparadorRango(xi:Int, xf:Int, yi:Int, yf:Int):(Int,Int)=>(Boolean) = { (x:Int, y:Int) => { x >= xi && x <= xf && y >= yi && y <= yf } };
Tree with Level-Order Traversal
This defines a Tree
class with a method for getting nodes at a specific level.
case class Tree(val dato:Int, val hijos: List[Tree]){ def nodosNiveli(i:Int):List[Int] = { if(i == 1) List(dato) else if(hijos.isEmpty) List() else hijos.map(_.nodosNiveli(i-1)).foldRight(Nil.asInstanceOf[List[Int]])(_ ::: _) } }
2D Point with Getters and Setters
This defines a Punto2D
class with explicit getters and setters for its coordinates.
class Punto2D(private var _x:Int, private var _y:Int){ def x = { println("hola") _x } // getters def y = _y def x_=(vx:Int) {_x = vx} // setters def y_=(vy:Int) {_y = vy} };
Generic Filter Function
The miFilter
function filters a list based on a given predicate.
def miFilter[A](lista: List[A], pred: (A)=>Boolean): List[A] = { if (lista.isEmpty) Nil else if (pred (lista.head)) lista.head :: miFilter(lista.tail, pred) else miFilter(lista.tail, pred) }