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
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
consoleto start and typeto quit Type
compileto compile the source code located in the directory src/main/scalaType
testto test the unit tests for the project located in src/test/scalaIf 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()) }
}
}
Comment code
Comment one line
Comment multiple lines