We'll dive into Scala collections later, but to get started, we'll mention a few now.
There are three types of collections: sequences, sets, and maps. These can further be categorized as mutable (we can add and remove members) and immutable.
Collections are generic, parameterized by the type of element they contain. For example:
Array[Int] // = the type of all arrays containing integers.
We can think of a sequence as a function that takes a position as input and returns the element in the sequence at that position:
myArray(0) // = first element of myArray
If the sequence members are variables, we can update the element at a position with syntax like this:
myArray(0) = 100 // update variable at position 0
Scala collections methods are very uniform. They all have pretty much the same methods and we can iterate over them using a for-loops:
for(i <- myArray) ...
A range is a bounded subsequence of a sequence or ordered type. We have seen ranges used with the for-loop:
scala> for(d <- 0 to 9) print(d)
0123456789
scala> for(d <- 0 until 9) print(d)
012345678
scala> for(d <- 0 to 9 by 2) print(d)
02468
scala> for(d <- 9 to 0 by -1) print(d)
9876543210
We can use sequences in other ways:
val digits = 0 to 9
def isDigit(n: Int) = digits contains n // same as digits.contains(n)
scala> isDigit(5)
val res7: Boolean = true
scala> isDigit(10)
val res8: Boolean = false
An array is an indexed sequence of contiguous variables.
Creating an array of values is simple:
val days = Array("Monday", "Tuesday",
"Wednesday", "Thursday", "Friday",
"Saturday", "Sunday")
Like all sequences, we can iterate over arrays:
scala> for(day <- days) println(day)
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Or we can iterate over the indices of an array:
scala> for(i <- 0 until days.length) println(days(i))
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Notice that we use parentheses instead of square braces to access array elements.
Even though days is a constant array, its components are still variables that can be updated:
scala> days(2) = "Hump Day"
scala> days
res19: Array[String] = Array(Monday, Tuesday, Hump Day, Thursday, Friday,
Saturday, Sunday)
We can declare and fill an array in two steps:
var squares = Array.ofDim[Int](10)
for(i <- 0 until 10) squares(i) = i * i
scala> for(square <- squares) println(square)
0
1
4
9
16
25
36
49
64
81
We can do lots of things to arrays (see the Scala docs on this). For example, we can add an element to the end of an array:
scala> squares :+ 100
val res15: Array[Int] = Array(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
scala> squares
val res16: Array[Int] = Array(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
scala> squares = squares :+ 100
squares: Array[Int] = Array(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
scala> squares
val res17: Array[Int] = Array(0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
Notice that the first expression didn't change squares. That's because arrays are immutable. But because squares is a variable containing a pointer to an array we can have it point to a new array.
A string is an immutable sequence of characters. Scala strings are Java strings with a few extra features that will be introduced later.
A sample session:
-> apple
appleay
-> peach
eachpay
-> 100
100
-> quit
uitqay
-> !quit
bye
A sample session:
-> add 12 25
37.0
-> mul 3.2 4
12.8
-> div 4 2
Unrecognized operator: div
-> add 2 3 4
command syntax: OP NUM NUM
-> add 2 ten
For input string: "ten"
-> quit
bye
A tuple is a sequence of values:
scala> val record = ("Carl Larc", "male",
25)
record: (String, String, Int) = (Carl Larc,male,25)
We can access the components of a tuple:
scala> record(0)
res31: String = Carl Larc
scala> record(1)
res32: String = male
scala> record(2)
res33: Int = 25
scala> record(3)
ERROR
A cool feature is a compound declaration that extracts the components of a tuple and assigns them to variables or constants:
scala> val (name, gender, age) = record
name: String = Carl Larc
gender: String = male
age: Int = 25
scala> name
res28: String = Carl Larc
scala> gender
res29: String = male
scala> age
res30: Int = 25
Tuples are useful for functions that need to return more than one value:
def toPolar(crt: (Double, Double)) = {
val (xc, yc) = crt
val r = math.sqrt(xc * xc + yc * yc)
val theta = math.acos(xc/yc)
(r, theta)
}
toPolar((1, 1)) // =
(1.4142135623730951,0.0)
toPolar((0, 1)) // =
(1.0,1.5707963267948966)
A map is a collection of key-value pairs, usually implemented as a tree or hash table.
val gender = Map(1->"male",
2->"female", 3->"transgender",
4->"unspecified")
scala> gender(3)
res0: String = transgender
scala> gender(0)
java.util.NoSuchElementException: key not found: 0
By default, maps are immutable. This means that once created, pairs can't be added, removed, or modified:
scala> gender(1) = "man"
<console>:9: error: value update is not a member of
scala.collection.immutable.Map[Int,String]
Here's how to declare a mutable map:
val scores = collection.mutable.Map("smith"->90,
"jones"->86, "simpson"->67)
scores("smith")
// = 90
scores("jones") // = 86
scores("hanson") // key not found: hanson
Oops, we forgot poor Hanson. Not a problem for mutable maps:
scores += "hanson"->100
scores("hanson") // = 100
If a student drops the course, we can delete them from the map:
scores -= "jones"
Smith is begging for 5 more points, here's how we handle it:
scores("smith") = scores("smith") + 5
The following code shows how to build a concordance from a text file. A concordance is a map of type Map[String, Int]. A member such as ("gadzooks", 3) says that the word "gadzooks" occurred three times in the document.
import scala.io.Source
object Concordance extends App {
var fTable = new
scala.collection.mutable.HashMap[String, Int] // our frequencey table
val wordPattern =
"[a-zA-Z]+".r // this is how to turn a string into a regular
expression
val source = Source.fromFile(args(0),
"UTF-8") // source file specified in command line
val lineIterator = source.getLines
for(line <- lineIterator) {
for(nextWord <-
wordPattern.findAllIn(line)) {
fTable(nextWord.toLowerCase) =
fTable.getOrElse(nextWord.toLowerCase, 0) + 1
}
}
for((k, v) <- fTable) println(k +
": " + v)
}
Notes:
table.getOrElse(key, default) = default if no value is associated with key
Here's a document:
to be or not to be,
that is the question.
A question to be sure.
I sure am thirsty.
May I ask for some ale?
Hello?
Was that the wrong question to ask?
Here's the concordance produced:
wrong: 1
am: 1
is: 1
not: 1
ask: 2
some: 1
or: 1
question: 3
be: 3
to: 4
sure: 2
that: 2
thirsty: 1
for: 1
a: 1
was: 1
ale: 1
the: 2
i: 2
hello: 1
may: 1
Enumerations are new to Scala 3.0. Here's an example:
enum Heading {
case north, south, east, west
}
There are several cool features of Scala enumerations:
scala> Heading.north.ordinal
val res18: Int = 0
scala> Heading.fromOrdinal(2)
val res19: Heading = east
scala> Heading.values
val res20: Array[Heading] = Array(north, south, east, west)
scala> Heading.valueOf("west")
val res21: Heading = west
Although break and continue aren't in the Scala, a more general form of break can be imported from the scala library:
import
scala.util.control.Breaks._
object TestBreak {
def
main(args: Array[String]): Unit = {
println("entering
main")
breakable {
println("A")
breakable {
println("B")
break
println("C")
}
println("D")
break
println("E")
}
println("exiting
main")
}
}
Output:
entering main
A
B
D
exiting main