Lambda Expression in Scala

Lambda Expression in Scala

Lambda Expression refers to an expression that uses an anonymous function instead of variable or value. Lambda expressions are more convenient when we have a simple function to be used in one place. These expressions are faster and more expressive than defining a whole function. We can make our lambda expressions reusable for any kind of transformations. It can iterate over a collection of objects and perform some kind of transformation to them.

Syntax:

val lambda_exp = (variable:Type) => Transformation_Expression

Example:

// lambda expression to find double of x

val ex = (x:Int) => x + x

 

Example :

// Scala program to show

// working of lambda expressio

// Creating object

object GfG   

// Main method

def main(args:Array[String])

    // lambda expression

    val ex1 = (x:Int) => x + 2

    // with multiple parameters

    val ex2 = (x:Int, y:Int) => x * y

    println(ex1(7))

    println(ex2(2, 3))

}

}

Output:

9

6

// Scala program to apply

// transformation on collection

// Creating object

object GfG

{

    // Main method

    def main(args:Array[String])

    {

        // list of numbers

        val l1 = List(1, 1, 2, 3, 5, 8)

        val l2 = List(13, 21, 34)

        // reusable lambda

        val func = (x:Int) => x * x

        // squaring each element of the lists

        val res1 = l1.map( func )

        val res2 = l2.map( func )

        println(res1)

        println(res2)

    }

}

Output:

List(1, 1, 4, 9, 25, 64)

List(169, 441, 1156)

 

 FUNCTIONAL DATA STRUCTURES

In this chapter you’ll switch gears to begin a fun and interesting part of the Scala language: Scala collections which broadly support two categories of data structures—immutable and mutable.

 A mutable collection can be updated or extended in place. This means you can change, add, or remove elements of a collection as a side effect. Immutable collections, by contrast, never change.

To understand and benefit from Scala collections, you need to know two concepts: type parameterization and higher-order functions. Type parameterization allows you to create types that take another type as a parameter (similar to Java generics). Higher-order functions let you create functions that take other functions as parameters. These two concepts allow you to create generic and reusable components, like Scala collections.

The Scala collection is one of Scala’s most powerful features. The library implements all the common data structures you need, making it essential for every Scala developer. A recent addition to the collections library is parallel collections. Scala parallel collections allow you to solve data parallelism problems in Scala with ease. You’ll see how the Scala parallel collections library helps when working with large datasets, so buckle up! This will be a fun and exciting ride.

 

ListMap in Scala

Immutable maps Implemented by using a list-based data structure. The Scala List class holds a sequenced, linear list of items. We must import scala.collection.mutable.ListMap for ListMap. ListMap collection used only for a small number of elements.

Syntax:

 

var listMapName = ListMap("k1"->"v1", "k2"->"v2", "k3"->"v3", ...)

Here, k is key and v is value.

 

Creating an ListMap:

In below code we can see a ListMap is created with values.

// Scala program to create or print ListMap

import scala.collection.immutable.ListMap

// Creating object 

object Geeks 

    // Main method 

    def main(args: Array[String]) 

    { 

        // Creating ListMap with values

        var listMap = ListMap("C"->"Csharp", "S"->"Scala", "J"->"Java")

        // Printing ListMap

        println(listMap) 

    } 

Output:

Map(C -> Csharp, S -> Scala, J -> Java)

 

Adding and accessing elements :

A ListMap is created, add elements and access elements also performed.

// Scala program to Adding and Accessing Elements ListMap

import scala.collection.mutable.ListMap

 

// Creating object

object Geeks

{

// Main method

def main(args: Array[String])

{

// Creating ListMap

var listMap = ListMap("C"->"Csharp", "S"->"Scala", "J"->"Java")

// Iterating elements

listMap.foreach

{

case (key, value) => println (key + " -> " + value)

}

// Accessing value by using key

println(listMap("S"))

// Adding element

var ListMap2 = listMap + ("P"->"Perl")

ListMap2.foreach

{

case (key, value) => println (key + " -> " + value)

}

}

}

 

Output:

J -> Java

C -> Csharp

S -> Scala

Scala

P -> Perl

C -> Csharp

J -> Java

S -> Scala

Removing an element from ListMap :

A ListMap is created than removing an element is performed using – sign. Below is the example to removing an element from ListMap.

// Scala program to removing Element from ListMap

import scala.collection.mutable.ListMap

// Creating object

object Geeks

{

// Main method

def main(args: Array[String])

{

// Creating ListMap

var listMap = ListMap("C"->"Csharp", "S"->"Scala", "J"->"Java")

// Iterating elements

listMap.foreach

{

case (key, value) => println (key + " -> " + value)

}

// Removing an element

listMap -= "C"

println("After Removing")

listMap.foreach

{

case (key, value) => println (key + " -> " + value)

}

}

}

Output:

J -> Java

C -> Csharp

S -> Scala

After Removing

J -> Java

S -> Scala

 

Creating an empty ListMap:

An empty ListMap is created either by calling its constructor or using ListMap.empty method.

// Scala program to Create an empty ListMap

import scala.collection.mutable.ListMap

 

// Creating object

object Geeks

{

// Main method

def main(args: Array[String])

{

// Creating an empty list map by calling constructor

var ListMap1 = new ListMap()

// Creating an empty list map by using .empty method

var ListMap2 = ListMap.empty

// Printing empty ListMap

println(emptyListMap1)

println(emptyListMap2)

}

}

Output:

Map()

Map()

 

Scala | Lazy Evaluation

Lazy evaluation or call-by-need is a evaluation strategy where an expression isn’t evaluated until its first use i.e to postpone the evaluation till its demanded. Functional programming languages like Haskell use this strategy extensively. C, C++ are called strict languages who evaluate the expression as soon as it’s declared. Then there are languages like Scala who are strict by default but can be lazy if specified explicitly i.e. of mixed type.

Let’s see an example in Scala:

Without lazy:

val geeks = List(1, 2, 3, 4, 5)

val output = geeks.map(l=> l*2)

println(output)

 

 

The value of output is calculated as soon as the operation is applied on it.

With lazy:

val geeks = List(1, 2, 3, 4, 5)

lazy val output2 = geeks.map(l=> l*2)

println(output2)

 

The value isn’t calculated till we use output2 that’s till println(output2).

Why lazy evaluation?


In the example what if we never use the output value? We wasted our map operation (CPU computations) which can be very costly when we write more complex and bigger code. Here lazy evaluation helps us in optimizing the process by evaluating the expression only when it’s needed and avoiding unnecessary overhead.

Pros:

· Optimizes the computation process. Spark a big data computation engine uses this technique at it’s core.

· Lazy evaluation can help us to resolve circular dependencies.

· Gives access to infinite data structure.

· Allows modularity of code into parts.

· The programmer lose control over the sequence their code is executed as some expressions are evaluated and others aren’t depending on the need.

Cons:

· Finding bugs can be tricky as programmer has no control over program execution.

· Can increase space complexity as all the instructions(operations) have to stored.

· Harder to code in contrast with conventional approach.

Lazy function values in Higher Order functions

We created one Higer Order function example earlier and cached the function value. However, we learned that Scala evaluates the function immediately as we cache it. In that scenario, even if we do not use the cached value, the function gets evaluated at the time of caching.

The following example uses a lazy val to cache the function value. This simple technique makes the function value lazy, and instead of immediate evaluation, the function value is evaluated once at the time of its first use.

 //define the function

 def twice(f: => Int) = {

   lazy val i = f

   println("We did not use i yet")

   i + i

 }

 

//call the function

 twice(factorial(15) / factorial(11))

 /* Output:-

     We did not use i yet

     Starting Factorial for 15

     Starting Factorial for 11

     res1: Int = 100

  */

Benefits of lazy evaluation

Are you wondering about the benefits? Why would you want to use the lazy evaluations? The laziness is mostly used to create data structures to handle large data volumes efficiently. Apache Spark libraries are the most common examples. If you know Spark RDD, they implement all transformations as lazy operations. Let's take an example to understand the benefits. I have a log file. There are different types of entries. Every line in the file has a record type of notice, error or info. We want to extract first two error messages.

Here is a simple Scala code to do that.

 

import scala.io._

 val s = Source.fromFile("error_log") .getLines() .toList.filter(_.contains("[error]"))

   .take(2) s foreach println

The above code gives me what I was looking for. However, did you notice that how this code works? We open the file, read all the lines and convert it to a list. Then we filter for all the lines that contain error. Finally, we take only first two of those lines. Assuming that my file is large, maybe few GBs, Is this an efficient method? I mean, I can create a simple loop. Read the file line by line until I get two error lines, and stop as soon as I get two error messages. That could be more efficient. Isn't it. I may get first two error messages at the beginning and avoid time and memory to process rest of the data. However, the example shown above is reading all the lines. It happens because the List is a strict data structure. When we call toList function, It evaluates immediately. So, we get all the lines from the file even before we apply a filter to it. Scala gives you a lazy alternative to lists. They call it Stream.


 

 

 

To view or add a comment, sign in

More articles by Konjeti Gnanendra Manjunadh

  • Getting Started with Hadoop

    Table of Contents What is Hadoop? Hadoop Through an Analogy The Rise of Big Data Big Data and its Challenges Who Uses…

  • SDP - 2 (User Research)

    SDP stands for the Skill development project. It is a crucial project that is given to every student in KL-University…

Others also viewed

Explore content categories