Showing posts with label scala. Show all posts
Showing posts with label scala. Show all posts

Monday, 16 May 2022

Scala Function - distinct and distinctBy

 Distinct - It creates a copy of a given collection without duplicated elements

DistinctBy - It also creates a copy given collection by keeping only one of the elements that produce the same key after applying the given anonymous function.

In below example:

if we apply isGreaterThan2 function to List(5,4,3,33,2,1,1), the keys will be generated as (true, true, true,true,false,false,false)

Thus it will only keep first element "5" which true and another element "2" which is false and rest will be ignored.


def distinctExample(): Unit = {
    val input1 = List(5,4,3,33,2,1,1)
    val distinctInput1 = input1.distinct
    println(s"distinctInput1 = $distinctInput1") // List(5, 4, 3, 33, 2, 1)

    val multiplyBy2 = ( num: Int ) => num * 2
    val distinctByInput1 = input1.distinctBy(multiplyBy2)
    println(s"distinctByInput1 = $distinctByInput1") // List(5, 4, 3, 33, 2, 1)

    val isGreaterThan2 = ( num: Int ) => num > 2
    val distinctByInput1ForGreaterThan2 = input1.distinctBy(isGreaterThan2)
    println(s"distinctByInput1ForGreaterThan2 = $distinctByInput1ForGreaterThan2") //List(5, 2)

  }



Scala Function - Diff

 Diff computes the difference  between LHS and RHS collection


 def diffExample(): Unit = {
    val input1 = List(5,4,3,2,1)
    val input2 = List(1,2,3)
    println(s"input1 diff input2 ${input1 diff input2}")//5,4
    println(s"input2 diff input1 ${input2 diff input1}") //Empty
  }

Scala Function - Count

Count defines how many elements in a given collection satisfy the input predicate.

 def countExample(): Unit = {
    def isEven = (input: Int) => (input % 2 == 0)
    val numberList = List(1,2,3,4,5,6,7,8,9,10)
    val totalEvenNumbersInList =numberList.count(isEven)
    println(s"Total Even Numbers in List = ${totalEvenNumbersInList}") //5
  }





Scala Function - Corresponds

The corresponds checks two collection indexes by index using the given predicate. 

Here isEven is a predicate that checks whether input numbers are even or not.

If this predicate returns for all the elements then corresponds will return true else false.

  def correspondsExample(): Unit = {
    def isEven = (input: Int, otherInput: Int) => (input % 2 == 0 && otherInput %2 ==0)
    val numberList = List(2,4,6,7)
    val numberList1 = List(22,24,26,28)
    val output: Boolean = numberList.corresponds(numberList1)(isEven)
    println(s"Comparing two list using corresponds - example1 : ${output}") //false

    val numberList2 = List(2,4,6)
    val numberList3 = List(32,44,88)
    val output1: Boolean = numberList2.corresponds(numberList3)(isEven)
    println(s"Comparing two list using corresponds - example1 : ${output1}") // true
  }


Saturday, 7 May 2022

Scala Function Const

Function.Const create an anonymous function which return same output for any input or some fixed input.

In below example it gives output 12 for any input. 


object MyBlog {
  def main(args: Array[String]): Unit = {
    constExample()
  }

  def constExample(): Unit = {
    val res: Any => Int = Function.const(12)
    val result = res("passAnything")
    println(s"Result by passing anything : ${result}" ) // result will be constant for any input as 12.
   
    //This can be useful to pass to higher order function
    val someList = List("anything", 8, 1298)
    val listWithSameElement = someList.map(Function.const(12))
    println(s"Function.Const pass as higher order function ${listWithSameElement}") //List(12, 12, 12)
  }

}


Scala Function - Cond

 Cond function with Either type accepts an anonymous function which returns a boolean. If the anonymous function returns true then cond returns Right else Left.

Cond with PartialFunction accepts the value and passes it to partialFunction which returns a boolean. If a partial function returns true then cond returns true else false.

CondOpt works similar to Cond except it return None for false.

object MyBlog {
  def main(args: Array[String]): Unit = {
    condExample()
  }


  def condExample(): Unit = {
    val isAbove18 = (input: Int) => input > 18
    val res: Either[String, String] = Either.cond(isAbove18(20), "True", "False")
    println(s"Cond with Either: ${res}") // Right(True)

    val canDivide: PartialFunction[Int, Boolean] = {
      case input: Int if(input != 0 )  => true
    }

    val res2: Boolean = PartialFunction.cond(0)(canDivide)
    println(s"Partial Function with Cond: ${res2}")

    val res3: Option[Boolean] = PartialFunction.condOpt(0)(canDivide)
    println(s"Partial Function with condOpt: ${res3}") //None

    val res4 =  canDivide(0)
    println(s"${res4}") // MatchError: 0 (of class java.lang.Integer)

  }











Scala Function - concat

Concat create new collection by adding given collections


object MyBlog {
  def main(args: Array[String]): Unit = {
    concatExample()
  }


  def concatExample(): Unit = {
    val input1 = List(1,2,3,4,5)
    val input2 = List(11,12,13,14,15)
    val res = input1 concat(input2)
    println(res) //List(1, 2, 3, 4, 5, 11, 12, 13, 14, 15)
  }
}









Scala Function - Compose

Scala compose creates an anonymous function which execute the function  from right hand side and pass output to left hand side function as input.

object MyBlog {
  def main(args: Array[String]): Unit = {
    composeExample()
  }

  def composeExample(): Unit = {
    def appendCharAB = (input: Int) => { println("Executing function appendCharAB"); input + "AB" }
    def appendCharXY = (input: String) => { println("Executing function appendCharAB"); input + "XY" }

    val composeAnonymousFunction: Int => String = appendCharXY compose(appendCharAB)
    val res = composeAnonymousFunction(999)
    println(res) //999ABXY
  }
}

Thursday, 5 May 2022

Scala Function - Combinations

 Scala Collection - Combinations

combinations creates the list of all the possible combinations from given collection by taking "n" number of element at a time.


object MyBlog {
  def main(args: Array[String]): Unit = {
    combinationExample()
  }

  def combinationExample(): Unit = {
    val input = List(1,2,3)
    val combinations = input.combinations(2)
    println(combinations.toList) //List(List(1, 2), List(1, 3), List(2, 3))
  }
}






Scala Function - Collect

Scala Collection Collect

Collect apply given partial function on each element of input collection and it discard elements for which partial function is not defined.


object MyBlog {
  def main(args: Array[String]): Unit = {
    collectExample()
  }

  def collectExample(): Unit = {
    val divide: PartialFunction[Int, Int] = {
      case input: Int if(input != 0) => 100/input
    }
    val inputList = List(0, 0, 5, 15, 20)
    val res = inputList.collect(divide) // List(20, 6, 5) 100/5, 100/15, 100/20
    println(res)
  }
}






Scala Function - Chain

 Scala Collection - Chain:

Scala chain execute multiple function in sequence while taking same input type data as input.


object MyBlog {
  def main(args: Array[String]): Unit = {
    chainExample()
  }

  def chainExample() : Unit = {
    def appendCharAB = (input: String) => input + "AB"
    def appendCharXY = (input: String) => input + "XY"
    val res = Function.chain(List(appendCharAB, appendCharXY))("Prashant")
    println(s"Res = ${res}" ) //PrashantABXY

    def appendCharAB1 = (input: Int) => input + "AB1"
    def appendCharXY1 = (input: String) => input + "XY1"
    /*
      Below is not allowed as function appendCharAB1 should accept string not int
      val res1 = Function.chain(List(appendCharAB1, appendCharXY1))("Prashant")
      This is okay in andThen
    */
  }

}





Scala Function - andThen

 Scala Collection andThen:


andThen creates an anonymous function that pass input to first function and it's output pass to second function

Both function can take different data types as input.

Note: Scala chain is similar to andThen only difference is that it can chain multiple functions and all function should have input with same data type.

object MyBlog {
  def main(args: Array[String]): Unit = {
    andThenExample()
  }

   def andThenExample() : Unit = {
    val add10 = (x:Int) => x + 10
    val add20 = (x:Int) => x + 20
    val addthen = add10 andThen(add20)
    val res = addthen(10)
    // 10 is passed to add10 and then it's output 20 pass to
    // next function add20.
    println(res) // 10 + 10 = add20(20) // 40
  }

}

Wednesday, 4 May 2022

Scala Function - aggregateExample

Scala Collection - aggregateExample

Use with Par function - It will split input in multiple collection and execute them parallel into 2 steps, first is sequence op and second is combine operation.

If we are not using aggregate with par function then we should use foldLeft.


object MyBlog {  
  def main(args: Array[String]): Unit = {  
   aggregateExample(List(1,2,3,4))  
  }  
  def aggregateExample(input: List[Int]): Unit = {  
   //Aggregate should be used with par to execute input parallel. input.par.aggregate  
   val output = input.aggregate((0,0))(  
    (acc, element) => (acc._1 + element, acc._2 + 1), // (1,1) (2,1) (3,1)(4,1)  
    (accu, element) => (accu._1 + element._1, accu._2 + element._2) // (1+2+3+4) (1+1+1+1) (10,4)  
   )  
   println("Output: " + output) // (10,4)  
   //Use foldLeft if we are not using par.  
   val outputWithFoldLeft = input.foldLeft((0,0))((acc,ele) => (acc._1 + ele, acc._2 + 1) )  
   println("Output with FoldLeft: " + outputWithFoldLeft) //(10,4)  
  }  
 }  




Tuesday, 29 May 2018

Self Type

Self type is a way to tell trait that it depends on another trait. We can achieve dependency injection of trait using self type

trait Targaryen {
  val name = "The House Targaryen"
}

tait History {
  this: Targaryen => // We are saying here History depends/required Targaryen
  def history : Unit = {
     println(s"$name ruled royal House of the Seven Kingdoms for three centuries")
  }
}

object GameOfThrones extends History with  Targaryen { //We mixed Targaryen because History required it
  def main(args: Array[String]): Unit = {
    GameOfThrones.history //The House Targaryen ruled royal House of the Seven Kingdoms for three centuries
  }
}


In History trait, method history will get $name from trait Targaryen.

Self type is denoted by "=>", in History trait, it declared as "this: Targaryen =>", We can replace "this" with any other name.

However, It's convention in Scala to use this.

When we extend History trait, self type makes compulsion to provide trait implementation of Targaryen so we mixed Targaryen in GameOfThrones object.

Cake design pattern is depends on self type.

Another advantage is that, if some trait Daenerys extends trait Targaryen then we can mix it with History

trait  Daenerys extends  Targaryen {
    def dracarys  = "Breathe fire!"
}

object GameOfThrones extends History with  Daenerys {
  def main(args: Array[String]): Unit = {
   println(GameOfThrones.dracarys)
  }
}

Compound type

Sometimes it is necessary to express that the type of an object is a subtype of several other types. In Scala, this can be expressed with the help of compound types

In Java when we implement two interfaces, to call the method from each interface, we might need to pass multiple objects, This can be avoided by Scala's compound type.

  trait Batting {
    def batting: Unit = {
      println("Do Batting")
    }
  }

  trait Bowling {
    def bowling : Unit = {
      println("Do Bowling")
    }
  }

  class AllRounder extends Batting with Bowling {

    def battingAndBowling(allRounder: Batting with Bowling) :Unit = {
        allRounder.batting
        allRounder.bowling
    }

    battingAndBowling(new AllRounder)

  }

  In a class AllRounder, method battingAndBowling takes a parameter which can do Bowling and Batting.

  If we wanted to achieve same in Java, we might have to change method as:

    Javaish approach

    public void battingAndBowling(Batting bt, Bowling bo) {
      bt.batting();
      bo.bowling();
    }
    battingAndBowling(New AllRounder(), new AllRounder())
   
    Note, we are passing two objects to call a respective method from the respective interface.

    Surely, we can avoid this:

    public <T extends Batting & Bowling> void battingAndBowling(T allRounder) {
      allRounder.call();
      allRounder.feed();
    }


 Scala does same in an elegant way!

Monday, 28 May 2018

Object in Scala

In Scala, objects are a singleton. Scala doesn’t have static class members (variables or methods). Instead, it has singleton objects.

Simple example of object:

object Person

As an object is a singleton, it does not have constructor  parameters.

Ex –

object Person(age: Int){} // Error
object Person(){} // Error
object Person{} // Success

object Person{
  val age : Int = 10
  var name : String = "Prashant"
  def bmi(height:Int, weight:Int) = weight/height
}

Above object has two parameters and one method. We can relate these parameters as static parameters in a java.

To call a method from the object, we don't need instance as doesn't require new keyword, we can call  method like "Person.bmi".

An object with the same class name in one file called companion object.
We can define apply(), unapply() and update() methods in an Object.

apply method is a special method in Scala. when we do obj(parameter), Scala calls obj.apply(parameter)

object Person {
   def apply() = {
    println("zero argument apply function")
  }

  def apply(a: Int, b: String) = {
    println("Two argument apply function")
  }

  def update(a: Int) = {
    println("Update : a : [" + a + "]")
  }

  def update(a: Int, b: Int, c: String) = {
    println("Update : a : [" + a + "] : [b] : [" + b + "] : [c] : [" + c + "]")
  }

}


object Client extends App { 
  Person
  Person()
  Person(1, "Hi..")
  Person() = 2
  Person(4, 5) = "Hello.."
}

Output :
zero argument apply function
Two argument apply function
Update : a : [2]
Update : a : [4] : [b] : [5] : [c] : [Hello..]

We can use apply method in a companion object as a Factory/builder.

Ex:
abstract class DatabaseDriver {
  // some database stuff
}

object DatabaseDriver {
  def apply(config: Configuration) = config.dbType match {
    case "MYSQL" => new MySqlDriver()
    case "PSQL" => new PostgresDriver()
    case _ => new GenericDriver()
  }
}

val mydatabase = DatabaseDriver(dbConfig)

internally it will call

val mydatabase = DatabaseDriver.apply(dbConfig)

We can override apply method several times, to get the different behavior.

Wednesday, 20 December 2017

Scala apply and unapply



apply and unapply are the special methods in Scala. The apply method works like a constructor. Unapply uses to extract the object. The unapply method used for pattern matching.

In another word, we also call them extractor.

package scala.practice

/**  * Created by prashant on 19/12/17.  */object Foo {

  def apply(maths:Int, science:Int): Int ={
      println("I am from apply method")
      maths+science
  }

  def unapply(maths: Int): Option[String] ={
    println("I am from unapply method")
    if(maths> 40) Some("Passed") else None
  }

  def main(args: Array[String]): Unit = {
    val fooObj = Foo(10,10); //I am in apply method
//   val Foo(res) = fooObj;

//    println("Res: "+ res)  // This will cause matcherror.
    fooObj match {
      case Foo(res) => println("Test Passed") //This line will call a unapply method.

      case _ => println("Test failed")
    }
  }

}


apply and unapply need not be opposite to each other.

apply is simple, Whenever we call Object(a,b,c) it internally calls Object.apply(a,b,c). The apply method can have zero or more parameter.

The unapply method is a bit complicated!

    val fooObj = Foo(10,10); //I am in apply method   //Line 1 

    //val Foo(res) = fooObj;   //Line 2 

in line number 2, Scala compiler executing unapply method.  It internally calls,
   val res =Foo.unapply(fooObj).get

Unapply method return type could be boolean or Optional.

The unapply method CAN NOT HAVE MORE THAN ONE PARAMETER, IT SHOULD ALWAYS HAVE SINGLE PARAMETER.

The reason behind that,

 fooObj match {
      case Foo(res) => println("Test Passed") //This line will call a unapply method.      case _ => println("Test failed")
    }


In above code, fooObj is an input parameter for an unapply method, We can not match more than one parameter so unapply never have multiple parameters. If there is no match, It will throw  "scala.MatchError"  error.

In above code as unapply method return None, which matches with "case_ =>", so it does not throw any error.

//    val Foo(res) = fooObj;   //Line 2 

In above code result "None" does not match So It throws an error.

Summary: apply method used to CONSTRUCT the object and unapply used to extract the object.


Thursday, 14 December 2017

Scala Call by Value Vs Call by Name






Call by value - evaluates the function arguments before calling the function
Call by name - evaluates the function first, and then evaluates the arguments if need be

Scala uses call-by-value by default, but it switches to call-by-name evaluation if the
parameter type is preceded by =>.

Example:
Infinite loop function:
scala> def loop: Int = loop
loop: Int

function which return x parameter.(It does not required parameter y for evaluation)

scala> def getX(x: Int, y: Int) = x
getX: (Int,Int)Int

scala > getX(1,loop)
.....

It will go into Infinite loop as call by value evaluates parameter y which causes Infinite loop.

Let's make changes in function to make parameter y as call by name.

scala> def getX(x: Int, y: => Int) = x
getX: (Int,Int)Int

scala> getX(1,loop)
res0: Int = 1

Now Instead of Infinite loop we got result as 1 beacuse call by name evaluates argument/parameter if needed.

Call-by-value has the advantage that it avoids repeated evaluation of arguments.
Call-by-name has the advantage that it avoids evaluation of arguments when the
parameter is not used at all by the function