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