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)
}
