Scala notes I

Data types

Boolean  true or false 
Byte     8 bit signed value
Short    16 bit signed value
Char     16 bit unsigned Unicode character
Int      32 bit signed value
Long     64 bit signed value
Float    32 bit IEEE 754 single-precision float
Double   64 bit IEEE 754 double-precision float
String   A sequence of characters

Unit     Corresponds to no value
Null     null or empty references
Nothing  subtype of every other type; includes no ...
Any      The supertype of any type; any object is of ..
AnyRef   The supertype of any reference type

More on datatype: https://www.tutorialspoint.com/scala/scala_data_types.htm

Variables

// mutable variable: variable value can be changed
var myVar : String = "Foo" 
// imutable variable: variable value cannot be changed
val myVar : Int = 10
// Note: scala will detect the data types by the initial values.
val x = {val a: Int = 200; val b: Int = 300; a+b}
// this value is not assigned until x is used (you are only using memory in demand)
lazy val x = 500

String

String interpolation

val name = "mark"
val age = 18
println(name + " is" + age + " year old.")
println(s"$name is $age years old.")
println(f"$name%s is $age%d years old.")  //typesafe: %s specifies string type and %d specifies double type
// mark is 18 years old.

println(raw"Hello \nworld.")
// Hello \nworld.
println(s"Hello \nworld.")
// Hello 
// world.

Methods for Strings

val str1: String = "Hello world";
val str2: String = " Max";

// calculate length
println(str1.length())  // returns 11

// concatenate
println(str1.concat(str2)) // returns "Hellow world Max"
println(str1 + str2)

// formating 
val num1 = 75;
val num2 = 100.25;
val result = printf("(%d -- %f -- %s)", num1, num2, str1);
println(result);
println("(%d -- %f -- %s)".format(num1, num2, str1));

Arrays

An array is a data structure which can store fixed-sized sequential elements of same data type.

val myarray: Array[Int] = new Array[Int](4);

// index starts from 0 in Scala
myarray(0) = 20; 
myarray(1) = 50; 
myarray(2) = 10; 
myarray(3) = 10;

// println(myarray) // won't work
for(x <- myarray){
  println(x);
}

// Default values of an array
val myarray2 = new Array[Int](5);  // default value is 0
val myarray2 = new Array[String](5);  // default value is null
val myarray2 = new Array[Double](5);  // default value is 0.0
val myarray2 = new Array[Boolean](5);  // default value is false

// concatenate 
import Array._
val myarray3 = Array(1, 2, 3, 5, 8);
println(myarray3.length)

val result = concat(myarray3, myarray3);
for(x <- result){
  println(x)
}

Collections

Lists

Lists are immutable and represent the link lists whereas arrays are mutable and flat.

val mylist: List[Int] = List(1, 2, 5, 8);
val names: List[String] = List("Max", "Tom", "John")
println(mylist)
println(names)
println(mylist(0))
//mylist(0) = 5  // cannot change the value of a list

println(0 :: mylist) // prepend 0 but won't change mylist
println(Nil)  // create a empty list
println(1 :: 5 :: 9 :: Nil) // create a list
println(List.fill(5)(2))  // returns List(2, 2, 2, 2, 2)

println(mylist.head)
println(names.tail) // print everything except for the first element
println(names.isEmpty)
println(mylist.reverse)
println(mylist.max)

// iterate over each element and run the given function
mylist.foreach( println )

var sum: Int = 0;
mylist.foreach( sum += _)
println(sum)   // sum up all the elements

Sets

A set is a collection of different elements of CM data types. So a set cannot have duplicated values inside them.

val myset: Set[Int] = Set(1, 2, 2, 5)
println(myset)  // returns Set(1, 2, 5)

By default, set is immutable in Scala. If we need to declare a mutable set, we can use scala.collection.mutable.Set instead.

val myset2 = scala.collection.mutable.Set(1, 3, 5)
println(myset2)

To add a value into the set

println(myset + 10)  
println(myset) // myset is not changed because it's immutable

Set is not ordered, which means the new element is assigned to a random location and you cannot index an element.

println(myset(8))  // check if 8 exists in myset or not

Other useful functions in set:

println(myset.head)
println(myset.tail)
println(myset.isEmpty)

// concatenate two sets
println(myset ++ myset2) 
println(myset.++(myset2))  

// find intersection of two sets
println(myset.&(myset2))
println(myset.intersect(myset2))

// find min & max
println(myset.min)
println(myset.max)

// for loop
myset.foreach(println)
for(x <- myset){ println(x) }

Maps

A map is a collection of key-value pairs, for example 801-max, 802-tom, 804-july.

val mymap : Map[Int, String] = Map(801 -> "max", 802 -> "tom", 804 -> "july");
println(mymap)
println(mymap(802))

Duplication of keys is not possible in a map.

val mymap : Map[Int, String] = Map(801 -> "max", 802 -> "tom", 804 -> "july", 804 -> "jully");
println(mymap); // it takes the last entry of 804
println(mymap.keys)  // returns a set
println(mymap.values)
println(mymap.isEmpty)
println(mymap.contains(801000)) // check if a key (or exception case) is valid/exist in the map

//for loop
mymap.keys.foreach{ key =>
  println("key " + key);
  println("value " + mymap(key));
}

//concatenate
val mymap2 : Map[Int, String] = Map( 805 -> "lua");
println(mymap ++ mymap2);

Tuples

A tuple is a class that can contain different kinds of elements, unlike array. A tuple is immutable in scala. You cannot change a tuple once it’s declared. A tuple can contain 22 elements at most.

val mytuple = (1, 2, "hello", true);
println(mytuple);

val mytuple2 = new Tuple3(1, 2, "hello"); // have to indicate the number of elements in a tuple right after the "Tuple" keyword; maximum number is 22.

println(mytuple._3) // returns the third element

val mytuple3 = new Tuple3(1, "hello", (2,3))
println(mytuple3._3._2); // print 3

//for loop
mytuple.productIterator.foreach{
  i => println(i) 
}

Options

An option is a container which can give you two values (Some or None).

val lst = List(1, 2, 3);
val map = Map(1 -> "Tom", 2 -> "Max", 3 -> "John");
println(lst.find(_ > 6));  // return None
println(lst.find(_ > 2));  // return Some(3)
println(map.get(1)); // return Some(Tom)
println(map.get(4)); // return None

// to abstract the values
println(lst.find(_ > 2).get); // return the element value 3
println(map.get(5).get); // get an exception error message

// to avoid exception error message
println(map.get(5).getOrElse("No name found.")); 

// to define options
val opt : Option[Int] = None;
println(opt.isEmpty); // returns true

val opt2 : Option[Int] = Some(55); // returns false

Comment code

Comment one line

// println("Hello")

Comment multiple lines

/*  
println("Hello")
println("world")
*/

Ifelse statement

val x = 20
var res = ""

if(x == 20){
  res = "x==20"
} else {
  res = "x!=20"
}
println(res)

val res2 = if(x == 20) "x==20" else "x!=20"
println(res2)

println(if(x == 20) "x==20" else "x!=20")

Use && for and and || for or.

Match expressions

val age: Int = 18

age match {
  case 18 => println("age 18")
  case 20 => println("age 20")
  case _ => println("default")  // catch default/unmatched case
}

// use as expression
val result = age match {
  case 18 => "age 18"
  case 20 => "age 20"
  case _ => "default"  // catch default/unmatched case
}
println("result = " + result)

// mutiple expressions
val i =8;
i match {
  case 1|3|5|7|9 => println("odd")
  case 2|4|6|8|10 => println("even")
}

Loops

while loop

check the condition before executing

var x = 0
while(x < 10){
    println("x = " + x)
    x += 1  // x = x + 1
}

do-while loop

execute at least once regardless of the condition

var y = 0
do {
    println("y = " + y)
    y += 1  
} while (y < 0);

for loop

for ( i <- 1 to 5){
  println("i using to " + i)
}
// identical
for ( i <- 1 until 6){
  println("i using to " + i)
}


for ( i <- 1 to 5; j <- 1 to 3){
println("i,j using to " + i + "," + j)
}


val lst = List(1, 5, 3, 2, 8)
for( i <- lst; if i < 3){
  println("i using to " + i)
}
// Use for loop as an expression
val result = for { i <- lst; if i < 3 } yield {
  i * i
}
println("result = " + result) // return a List

Map, flatten, and filter

Map method

val lst = List(1, 2, 3, 5, 7, 9, 10);
val mymap = Map(1 -> "Tom", 2 -> "Max", 3 -> "John");

// double every element in lst
println(lst.map(x => x*2))
println(lst.map(_ *2))

println(mymap.mapValues(x => "hi " + x));

// apply toUpper to every element in the string "hello"
println("hello".map(_.toUpper))

Flatten method

// flatten contents of a list of lists
println(List(List(1, 2, 3), List(3, 4, 5)).flatten)
println(lst.flatMap(x => List(x, x+1)))

Filter method

// abstract even numbers
println(lst.filter(x => x%2 == 0))

Reduce, fold, and scan (left/right)

Reduce method

val lst = List(1, 2, 3, 4, 6, 7, 8);
val lst2 = List("A", "B", "C");

println(lst.reduceLeft(_ + _)) // returns sum of all elements
println(lst2.reduceLeft(_ + _)) // returns "ABC" by (AB)C
println(lst2.reduceRight(_ + _)) // returns "ABC" by A(BC)

println(lst.reduceLeft((x, y) => {println(x + ",", + y); x+y;}))

Fold method is similar to reduce method but can insert initial argument.

println(lst.foldLeft(10)(_ + _)) // return 10 + sum(lst) 

Scan method takes initial value and applies it to each element in reduce method. It returns the map of intermediate results.

println(lst.scanLeft(10)(_ + _))
println(lst2.scanLeft("z")(_ + _))

Lazy evaluation

Lazy evaluation is an evaluation strategy that delays the evaluation of an expression until it’s needed. Scala supports strict evaluation by default and lazy evaluation if specified.

val e = 9; // strict evaluation
lazy val l = 9; // lazy evaluation

call-by-value v.s. call-by-name

# call-by-value, the general case
def method1(n: Int) {
  println("Method 1");
  println(n);
}

# call-by-name
def method2(n: => Int) {    // use => 
  println("Method 2");
  println(n);
}

val add = (a: Int, b: Int) => {
  println("Add");
  a + b
}

method1(add(5, 6))
// Add
// Method 1
// 11
method2(add(5, 6))
// Method 2
// Add
// 11

Scala in IntelliJ IDEA

SBT tasks

The following tasks can be run in sbt shell:

  • Scala interpreter: type console to start and type to quit

  • Type compile to compile the source code located in the directory src/main/scala

  • Type test to test the unit tests for the project located in src/test/scala

  • If your project has an object with a main method (or an object extending the trait App), then you can run the code in sbt easily by typing run. In case sbt finds multiple main methods, it will ask you which one you’d like to execute.

Unit test

package example

import java.util.NoSuchElementException

import org.scalatest.FunSuite
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner

/**
 * This class implements a ScalaTest test suite for the methods in object
 * `Lists` that need to be implemented as part of this assignment. A test
 * suite is simply a collection of individual tests for some specific
 * component of a program.
 *
 * A test suite is created by defining a class which extends the type
 * `org.scalatest.FunSuite`. When running ScalaTest, it will automatically
 * find this class and execute all of its tests.
 *
 * Adding the `@RunWith` annotation enables the test suite to be executed
 * inside eclipse using the built-in JUnit test runner.
 *
 * You have two options for running this test suite:
 *
 * - Start the sbt console and run the "test" command
 * - Right-click this file in eclipse and chose "Run As" - "JUnit Test"
 */
 @RunWith(classOf[JUnitRunner])
  class ListsSuite extends FunSuite {
 
  // We fist import all members of the `List` object.
  import Lists._

  test("sum of a few numbers") {
    assert(sum(List(1,2,0)) === 3)
    assert(sum(List(-2, -1, -5)) === -8)
    assert(sum(List(0, 0, 0)) === 0)
    assert(sum(List()) === 0)
  }

  test("max of a few numbers") {
    assert(max(List(3, 7, 2)) === 7)
    assert(max(List(-3, -7, -2)) === -2)
    assert(max(List(2, 2, 2)) === 2)
    assert(max(List(-3, 0, 3, -5)) === 3)
    intercept[NoSuchElementException]{ max(List()) }
  }

}
Avatar
Tingting Yu
Developer, Data Scientist

My research interests include time-series analysis, longitudinal analysis, image analysis …

Related