var a = 5 // variable
var b: Int = 5 // variable with explicit typing
val zero = 0 // constant
val name = "joe"
"Hello " + name + " how are you ?"
// or
s"Hello $name how are you ?"
s"2 + 2 = ${2+2}"
raw"\nature"// The "\n" is not escaped
printf("pi = %2.2f\n", 3.1415)
f"pi = ${3.1415}%2.2f"
"""1...
2...
3."""
// ou
"""1...
|2...
|3.""".stripMargin // stripMargin("#") to change the default value
{val a = 6; val b = 4; a + b}
def f: Int = {val a = 6; return a; val b = 7; a + b} // return interrupts the evaluation
scala.math.sin(3.14)
// or (when the function only takes one parameter)
scala.math.sin{3.14}
lazy val a = {println("Statement of a");1} // evaluate when the variable is called
val b = {println("Statement of b");2}
a+b
def a = 1
def sum(v1: Int, v2: Int) = v1 + v2
def sum1(v1: Int, v2: Int): Int = v1 + v2 // to indicate the type of return
def zeroOrx(x: Int = 0) = x // parameter with default value
s"${zeroOrx()}, ${zeroOrx(100)}"
def mean(x: Int*) = x.sum / x.size
mean(1, 2, 3, 4, 5)
// procedure (Unit): possibility to remove the "="
def unit() {println("Unit")}
val flagColor: (String, String, String) => String = (c1, c2, c3) => {c1 + " " + c2 + " " + c3}
// ou
val flagColor1 = (c1: String, c2: String, c3: String) => {c1 + " " + c2 + " " + c3}
if (scala.util.Random.nextFloat > 0.5) "win" else "loose"
scala.util.Random.nextInt match {
case 0 => println("zero")
case a if a > 0 => println("positive")
case a if a < 0 => println("negative")
case _ => println("end")
}
throw new Exception("...")
try {
1 / 0
} catch {
case ex: ArithmeticException => ex.printStackTrace()
case ex: Exception => ex.printStackTrace()
case _ => println("Nothing")
}
def hey[T](x: T) = "Hey " + x.toString
// equivalent to
def hey1(x: Any) = "Hey " + x.toString
hey[String]("Joe") + " " + hey1(122)
import Ordering.Implicits._
def greaterThan[T: Ordering](x: T, y: T): Boolean = x > y
moreThan(1, 3)
type ArrInt = Array[Int] // type alias
object Test {
def main(args: String*){
println("Hello world!")
}
}
class Money(startMoney: Int) {
def this() = this(0) // builder
private var contain: Int = 0
def +=(money: Int) = contain += money
def empty = {val solde = contain; contain = 0; solde}
def howMany = contain
override def toString = contain.toString
}
object Money {
// method and static variables
def foo = "bar"
}
val m = new Money()
m += 10
m.empty
Money.foo
val ints = new Array[Int](30) // empty array
val ints2 = Array[Int](1, 2, 3, 4) // array with init values
val matrix4x9 = Array.ofDim[Double](4, 9)
ints2(3)
ints2(3) = 1000
// or
ints2.update(3, 1000)
ints2(3)
val days = Array("Monday", "Tuesday", "Wednesday", "Thrusday", "Friday", "Saturday", "Sunday")
var i = 0
while(i < days.length){
println(days(i))
i += 1
}
for (i <- 0 until days.length) println(days(i))
for (day <- days) println(day)
days foreach println
val daysToUpperCase = for(day <- days) yield day.toUpperCase
val daysWithLetterE = for(day <- days if day.contains("e")) yield day
val ints = Array(1, 2, 3, 4)
val chars = Array('a', 'b', 'c', 'd')
for (int <- ints; char <- chars) yield int.toString + char.toString
Array(1, 2, 3, 4, 5).filter(x => x % 2 == 0)
Array(1, 2, 3, 4, 5).map(x => x*x)
Array(3, 6, 2, 0, 8, 5).sortWith((e1, e2) => e1 < e2)
Array(1, 2, 3, 4, 5).reduce((e1, e2) => e1+e2) // équivalent à Array(1, 2, 3, 4, 5).sum
import scala.collection.mutable.ArrayBuffer
val arr = ArrayBuffer[Int]()
arr += 25
arr += (1, 2, 3, 4)
arr.insert(2, 5, 5)
arr
arr ++= Array(99, 99)
arr.remove(4)
Lazy evaluation: Allows to delay the transformation operations and thus to calculate or store only if necessary.
Parallelization support: Method calls do not change. They are just calling in parallel instead of calling them one after the other.
Mutable: Write access.
Immutable: No write access.
Storage of values
val oneAndTwo = (1, 2)
val oneAndTwo1 = Tuple2(1, 2) // There are tuples that range from 1 element to 22
val oneAndTwo2 = 1 -> 2
s"${oneAndTwo._1}, ${oneAndTwo._2}"
val (a, b, _, d) = (1, 2, 3, 4) // "_" for a meaningless value
s"$a $b $d"
Key-value couple
val map = Map(("one", 1), ("two", 2))
val map1 = Map("one" -> 1, "two" -> 2)
map("two")
map.getOrElse("three", -1)
val mutableMap = scala.collection.mutable.Map[String, Int]()
mutableMap("three") = 3
mutableMap += (("one" -> 1), ("two" -> 2))
mutableMap -= "one"
mutableMap += "five" -> 5
val reverseMap = for((key, value) <- mutableMap) yield (value, key)
// or
mutableMap.map(element => (element._2, element._1))
s"keys: ${mutableMap.keys} values: ${mutableMap.values}"
mutableMap.partition(_._2 % 2 == 0) // cut a Map according to a predicate
import scala.collection.immutable
immutable.HashMap[AnyVal, AnyVal]()
immutable.IntMap[AnyVal]()
immutable.ListMap[AnyVal, AnyVal]()
immutable.LongMap[AnyVal]()
immutable.SortedMap[Int, AnyVal]()
immutable.TreeMap[Int, AnyVal]()
import scala.collection.mutable
mutable.HashMap[AnyVal, AnyVal]()
mutable.LinkedHashMap[AnyVal, AnyVal]()
mutable.ListMap[AnyVal, AnyVal]()
mutable.OpenHashMap[AnyVal, AnyVal]()
mutable.WeakHashMap[AnyVal, AnyVal]()
Presence (Some) or not (None) of value
val emptyOpt: Option[Int] = None
val fullOpt: Option[Int] = Some(42)
emptyOpt match {
case Some(value) => println(value)
case None => println("Empty")
}
fullOpt.get
emptyOpt.isEmpty
Choice between 2 return values
def divide(a: Double, b: Double): Either[String, Double] = {
if (b==0.0) Left("Division by zero") else Right(a/b)
}
divide(4, 0)
divide(4, 2)
Object sequence defined in recursive ways
val list = List(1, 2, 3, 4)
list.head
list.tail
list.tail.tail.head
list.tail.tail.tail.tail
Nil
1 :: List(2, 3, 4)
1 :: 2 :: 3 :: 4 :: Nil
list(3)
def lCount(lst: List[Int], func: (Int) => Boolean): Int = {
if (lst == Nil) 0 else
(if (func(lst.head)) 1 else 0) + lCount(lst.tail, func)
}
lCount(List(1, 2, 3, 4), _ % 2 == 0)
Non-ordered collection with each element present only once
val set = Set(1, 2, 3, 4)
set + 3
set contains 1
// or
set(1)
import scala.collection.immutable
immutable.BitSet()
immutable.HashSet[AnyVal]()
immutable.ListSet[AnyVal]()
immutable.TreeSet[Int]()
immutable.SortedSet[Int]()
import scala.collection.mutable
mutable.BitSet()
mutable.HashSet[AnyVal]()
mutable.LinkedHashSet[AnyVal]()
mutable.TreeSet[Int]()
Collection with acceptable performance in access and update.
val v = Vector(1, 2, 3, 4)
v :+ 5 :+ 6
v(1)
v updated(2, 10)
0 +: v
LIFO
val s = scala.collection.immutable.Stack[Int](1, 2, 3, 4)
s push(29) push(98)
s top
s pop // Remove the first element from the stack
FIFO
val q = scala.collection.immutable.Queue[Int](1, 2, 3, 4)
q enqueue(98) enqueue(76)
q dequeue
1 to 10
1 until 10
0 to 100 by 5
Lazy List, only the first occurrence is evaluated
val s = 1 #:: 2 #:: 3 #:: Stream.empty
Stream(1, 2, 3)
def fibonacci(a: Int, b: Int): Stream[Int] = a #:: fibonacci(b, a + b)
fibonacci(0, 1).take(10).force
Traversables collections implement foreach
, which allows the collection to be browsed by calling a function.
'a' to 'z' foreach print
Crossover collections implement iterator
, which allows access to each element without modification.
val ite = ('a' to 'z').iterator
while (ite.hasNext) print(ite.next)
The Seq collections are ordered.
val s = ('a' to 'z')
s(scala.util.Random.nextInt(25))
s.segmentLength(v => (v < 'd'), 1) // Length of the longest sequence according to a predicate and an index
s.prefixLength(v => (v < 'd')) // Length of the longest sequence according to a predicate from index 0
s.indexWhere(v => "hello world" contains v.toString) // first indice according to a predicate
s.lastIndexWhere(v => "hello world" contains v.toString) // last indice according to a predicate
s.indexOf('z')
s.startsWith(Seq('a', 'b'))
s.endsWith(Seq('y', 'z'))
s.reverse
s.indexOfSlice(Seq('k', 'l'))
Operation | Description | Collection |
---|---|---|
c + e ; c + (e1,..,en) | Add elements, return a new collection. | Map, Set |
c += e ; c += (e1,..,en) ; c -= e ; c -= (e1,..,en) | Adds and removes elements by modifying the collection. | Mutable |
c - e ; c - (e1,..,en) | Retire des éléments, retourne une nouvelle collection. | ArrayBuffer, Map, Set |
c :+ e ; e +: e | Remove items, return a new collection. | Seq |
e :: c | Add an element at the beginning. | List |
e #:: c | Add an element at the beginning. | Stream |
Operation | Description | Collection |
---|---|---|
c(k) = e ; c.update(k, e) | Updates the item in the indexed collection k. | mutable.Map, mutable.Seq |
c.updated(k, e) | New collection in which the element is updated. | Sauf Set. |
Opération | Description | Collection |
---|---|---|
c ++ c2 | Union. | Iterable |
c - c2 | c without the elements of c2 | ArrayBuffer, Map, Set |
c2 ++=: c | Add c2 at the top of c | ArrayBuffer |
c ++= c2 ; c -= c2 | Rajoute c2 à c ou enlève c2 à c | Mutable |
c diff c2 | Add c2 to c or remove c2 to c | Seq |
c ::: c2 | Union | List |
c | c2 ; c & c2 ; c &~ c2 | Union, Intersection et Difference | Set |
Seq(1).toArray
Seq(1).toBuffer
Seq(1).toList
Seq((1, 2)).toMap
Seq(1).toStream
Seq(1).toString
Seq(1).toVector
Seq(1).toTraversable
Seq(1).toIndexedSeq
Seq(1).toIterable
Set(1).toSeq
Seq(1).toSet
val collec = 1 to 100 by 8
collec.to[List] // in general
val collec = (1 to 100 by 6) ++ Seq(4)
collec.size
collec.count(_%2 == 0)
collec.isEmpty
collec.nonEmpty
collec.sameElements(collec)
collec.forall(_ > 0)
collec.exists(_ < 0)
collec.sum
collec.product
collec.min
collec.max
val collec = (1 to 100 by 6) ++ Seq(4)
collec.head
collec.last
collec.tail
collec.init
collec.take(5)
collec.drop(5)
collec.splitAt(5)
collec.takeRight(5)
collec.dropRight(5)
collec.takeWhile(_ < 30)
collec.dropWhile(_ < 30)
collec.span(_ < 30)
collec.filter(_ % 2 == 0)
collec.filterNot(_ % 2 == 0)
collec.partition(_ % 2 == 0)
collec.slice(3, 7)
collec.mkString(";")
collec.mkString("[", ",", "]")
def range(n: Int) = 0 to n
Seq(1, 2, 3, 4).map(range)
Seq(1, 2, 3, 4).flatMap(range) // merges collections
(1 to 5).reduceLeft(_-_)
(1 to 5).reduceRight(_-_)
Same thing as reduction but with an initial element.
((1 to 4) ++ (1 to 6)).foldLeft(Set[Int]())(_+_)
// number of occurrences
Seq(1, 2, 1, 1, 7, 7, 2, 9).foldLeft(Map[Int, Int]()) ((counter, e) => counter + (e -> (counter.getOrElse(e, 0) + 1)))
Same as fold by saving the intermediate results in a collection
Seq(1, 2, 4, 1, 3, 4).scanLeft(Set[Int]()) ((s, e) => s + e)
"abcde" zip 1.to(5)
"abcde".zipAll(1.to(2), "*", -1) // with default value on the left and right
"abcde" zipWithIndex
Seq((1, 2), (3, 4), (5, 6)) unzip
val s = Seq(5, 6, 2, 8, -3, 0, 2, 8)
s.indexOf(2)
s.lastIndexOf(2)
s.indexOfSlice(Seq(2, 8))
s.lastIndexOfSlice(Seq(2, 8))
s.indexWhere(_ % 2 == 0)
s.prefixLength(_ > 0)
s.segmentLength(_ > 0, 3)
s.contains(1)
s.containsSlice(Seq(8, -3))
s.startsWith(Seq(0))
s.endsWith(Seq(2, 8))
s.reverse
s.intersect(Seq(1, 7, 8, 3))
s.diff(Seq(1, 7, 8, 3, 2))
s.slice(0, 4).permutations.toList
s.slice(0, 4).combinations(2).toList
s.sorted
s.sortWith(_ > _)
s.sortBy(_ - scala.util.Random.nextInt(8)) // transforms the collection before sorting
To understand where a parallel collection can be useful, it helps to think about how they work. Conceptually, you can imagine a collection being split into different chunks; your algorithm is then applied to the chunks, and at the end of the operation, the different chunks are recombined. To be used only if the order is not important.
1 to 100 par
(1 to 100 par) seq
val start = System.nanoTime
val r = 0 to 1000000
for (i <- 0 to 100) {val cpt = r.count(_ % 3 == 0)}
s"${(System.nanoTime - start) / 1000}ms"
val start = System.nanoTime
val r = 0 to 1000000
for (i <- 0 to 100) {val cpt = r.par.count(_ % 3 == 0)}
s"${(System.nanoTime - start) / 1000}ms"
val v = (1 to 5).view.map(_ * 3)
println(v) // nothing is evaluated
println(v(3))
println(v.force)
class Money(startMoney: Int) {
def this() = this(0) // builder
private var contain: Int = 0
def +=(money: Int) = contain += money
def empty = {val solde = contain; contain = 0; solde}
def howMany = contain
override def toString = contain.toString
}
class ClassA{ // without indication the methods and variables are by default public
val bar = "foo"
def foo = "bar"
}
class ClassA {private val foo ="bar"} // access only for this
(new ClassA).foo
class ClassA {protected def hey(s: String) = println(s"Hey $s !")} // access for this and children
class ClassB extends ClassA {hey("John")}
new ClassB
class ClassC {
hey("John")
(new ClassA).hey("John")
}
Specified a restriction limit that can be this
, a package
, a class
or an object
: private[limit]
or protected[limit]
class Money {var amount = 0}
val money = new Money
money.amount = 100 //setter
money.amount //getter
class ClassA(attribute1: Int, attribute2: Int){ //main constructors
def this(){ // another constructor
this(0, 0)
}
override def toString: String = s"$attribute1, $attribute2"
}
new ClassA(30, 40).toString
new ClassA().toString
class ClassA(val attribute1: Int, private var attribute2: Int){ // attributes are accessible with getters and setters
def this(){ // another constructor
this(0, 0)
}
override def toString: String = s"$attribute1, $attribute2"
}
class Fraction(val numerator: Int, val denominator: Int){
require(denominator != 0, "denominator can't be equals 0")
}
new Fraction(1, 2)
new Fraction(1, 0)
class ClassA {
classAalias => // defined an alias for ClassA.this
val id = System.nanoTime
class ClassB {
def hey = println("Hello")
def id = ClassA.this.id // access the context of the surrounding class
def id2 = classAalias.id
}
def buildClassB = new ClassB
def bar(v: ClassA#ClassB) = println("Hello") // accepts all varieties of ClassA and ClassB
}
val a = new ClassA
val b = a.buildClassB
b.hey
a.bar(b)
println(a.id, b.id, b.id2)
val person = new {
val name: String = "John"
def presentation(): Unit = println(s"My name is $name.")
}
person.presentation()
def printName(person: {val name: String}) = { // {val name: String} is a type.
println(person.name)
}
printName(person)
class ClassA(var a: Int = 0) {
def update(newA: Int): this.type = {
a = newA
this
}
}
val a = new ClassA()
a.update(10) // return a new object
val obj1: Seq[Int] = Seq.empty
obj1.isInstanceOf[Iterable[Int]]
obj1.asInstanceOf[Iterable[Int]]
obj1.getClass
object Object { // Usually contains the static elements
val foo = 0
def bar = foo
}
Object.bar
class ClassA(var a: Int = 0) {
override def toString =s"$a"
override def equals(other: Any) = {
if (other.isInstanceOf[ClassA]) this.a == other.asInstanceOf[ClassA].a
else false
}
}
val a = new ClassA(10)
val b = new ClassA(99)
a.toString
a.equals(b) // ou a == b
object Foo {
def apply(name: String, suffix: String) = name + "." + suffix
def unapply(name: String): Option[(String, String)] = {
//simple argument extractor
val parts = name.split("\\.")
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}
val file = Foo("test", "txt")
val Foo(name) = file
case class File(name: String, suffix: String)
val file: File = File("test", "scala")
file.name
val File(name, suffix) = file
file.copy(name="test1")
class Insect
class Ant extends Insect
class Vehicle(brand: String, nbWheels: Int, fuel: Boolean)
class Bicycle(brand: String) extends Vehicle(brand, 2, false)
class Class1 {
def method = println("class1")
}
class Class2 extends Class1 {
override def method = println("class2")
}
val c = new Class2
c.method
abstract class Class1 {
var indefinedVar: Int
def undefinedMethod()
}
final class Class1
class Class2 extends Class1
class Class1 {
final def method = {}
}
class Class2 extends Class1 {
override def method = {}
}
implicit class StringFile(s: String) {
def splitFile: Option[(String, String)] = {
s.split('.') match {
case Array(name, suffix) => Some((name, suffix))
case _ => None
}
}
}
"hey".splitFile
"hey.scala".splitFile
object Fraction {
// Implicitly call by the compiler if it needs it
// An import is required: import Fraction.int2Fraction
implicit def int2Fraction(i: Int) = new Fraction(i, 1)
}
class Fraction(val numerator: Int, val denominator: Int) {
def +(f: Fraction) = new Fraction(numerator*f.denominator + f.numerator*denominator, denominator * f.denominator)
override def toString: String = s"$numerator/$denominator"
}
new Fraction(2, 3) + new Fraction (2, 1)
new Fraction(2, 3) + 2
trait Trait1 {
def foo = {}
}
trait Trait2 {
def bar = {}
}
class Class1 extends Trait1 with Trait2
class Class2
val c = new Class2 with Trait1
new Trait1