Uncategorized

Collections

Sequences
Sequences types let you work with groups of data lined up in order. Because the elements are ordered, you can ask for the first element, second element, 103rd element, and so on.
Lists
 
Lists sup- port fast addition and removal of items to the beginning of the list, but they do not provide fast access to arbitrary indexes because the implementation must iterate through the list linearly.
The immutability of lists helps you develop correct, efficient algorithms because you never need to make copies of a list. Described separately in another note.
Arrays
Arrays allow you to hold a sequence of elements and efficiently access an element at an arbitrary position, both to get or update the element, with a zero-based index. Here’s how you create an array whose size you know, but for which you don’t yet know the element values:
scala> val fiveInts = new Array[Int](5)
fiveInts: Array[Int] = Array(0, 0, 0, 0, 0)
Here’s how you initialize an array when you do know the element values:
scala> val fiveToOne = Array(5, 4, 3, 2, 1)
fiveToOne: Array[Int] = Array(5, 4, 3, 2, 1)
List buffers
ClassListprovides fast access to the head of the list, but not the end. Thus, when you need to build a list by appending to the end, you should consider building the list backwards by prepending elements to the front, then when you’re done, callingreverseto get the elements in the order you need. Another alternative, which avoids thereverseoperation, is to use aListBuffer. AListBufferis a mutable object (contained in packagescala.collection.mutable), which can help you build lists more effi- ciently when you need to append.ListBufferprovides constant time ap- pend and prepend operations. You append elements with the+=operator, and prepend them with the+=:operator. When you’re done building, you can obtain aListby invokingtoListon theListBuffer.
scala> val buf = new ListBuffer[Int]
buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> buf += 1
res4: buf.type = ListBuffer(1)

scala> buf += 2
res5: buf.type = ListBuffer(1, 2)

scala> 3 +=: buf
res7: buf.type = ListBuffer(3, 1, 2)

scala> buf.toList
res8: List[Int] = List(3, 1, 2)

Array buffers

An ArrayBuffer is like an array, except that you can additionally add and remove elements from the beginning and end of the sequence. All Array operations are available, though they are a little slower due to a layer of wrapping in the implementation. The new addition and removal operations are constant time on average. When you create an ArrayBuffer, you must specify a type parameter, but need not specify a length. The ArrayBuffer will adjust the allocated space automatically as needed.
scala> val buf = new ArrayBuffer[Int]()
buf: scala.collection.mutable.ArrayBuffer[Int] =ArrayBuffer()

scala> buf += 12
res9: buf.type = ArrayBuffer(12)

scala> buf += 15
res10: buf.type = ArrayBuffer(12, 15)
Strings (via StringOps)
Because Predef has an implicit conversion from String to StringOps, you can treat any string like a sequence:
scala> def hasUpperCase(s: String) = s.exists(_.isUpper)
hasUpperCase: (s: String)Boolean

scala> hasUpperCase("Robert Frost")
res14: Boolean = true

scala> hasUpperCase("e e cummings")
res15: Boolean = false
Because no method named “exists” is declared in class String itself, the Scala compiler will implicitly convert s to StringOps, which has the method. The exists method treats the string as a sequence of characters.
Sets and Maps
Big difference between Sets and Lists is that Sets members are unique. By default when you write “Set” or “Map” you get an immutable object. If you want the mutable variant, you need to do an explicit import. If you want to use both mutable and immutable sets or maps in the same source file, one approach is to import the name of the package that contains the mutable variants:
scala> import scala.collection.mutable
import scala.collection.mutable
You can continue to refer to the immutable set as Set, as before, but can now refer to the mutable set as mutable.Set. Here’s an example:
scala> val mutaSet = mutable.Set(1, 2, 3)
mutaSet: scala.collection.mutable.Set[Int] = Set(3, 1, 2)
The key characteristic of sets is that they will ensure that at most one of each object, as determined by ==, will be contained in the set at any one time.  Because sets exclude duplicates, each distinct word will appear exactly one time in the set:
scala> val text = "See Spot run. Run, Spot. Run!"
text: java.lang.String = See Spot run. Run, Spot. Run!

scala> val wordsArray = text.split("[ !,.]+")
wordsArray: Array[java.lang.String]= Array(See, Spot, run, Run, Spot, Run)

scala>  val words = mutable.Set.empty[String]
words: scala.collection.mutable.Set[String] = Set()

scala> for (word <- wordsArray)
         words += word.toLowerCase
scala> words
res17: scala.collection.mutable.Set[String]= Set(spot, run, see)
Maps let you associate a value with each element of the collection. Using a map looks similar to using an array, except that instead of indexing with integers counting from 0, you can use any kind of key. If you import the scala.collection.mutable package, you can create an empty mutable map like this:
scala> val map = mutable.Map.empty[String, Int]
map: scala.collection.mutable.Map[String,Int] = Map()

scala> map("hello") = 1
scala> map("there") = 2
scala> map
  res20: scala.collection.mutable.Map[String,Int] =Map(hello -> 1, there -> 2)
Default sets and maps
For sets with fewer than five elements, a special class devoted exclusively to sets of each particular size is used, to maximize performance. Once you request a set that has five or more elements in it, however, the factory method will return an implementation that uses hash tries. As with sets, for immutable maps with fewer than five elements, a special class devoted exclusively to maps of each particular size is used, to maximize performance. Once a map has five or more key-value pairs in it, however, an immutable HashMap is used.
Sorted sets and maps
You may need a set or map whose iterator returns elements in a particular order. For this purpose, the Scala collections library provides traits SortedSet and SortedMap. These traits are implemented by classes TreeSet and TreeMap.
scala> val ts = TreeSet(9, 3, 1, 8, 0, 2, 7, 4, 6, 5)
ts: scala.collection.immutable.TreeSet[Int] = TreeSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> val cs = TreeSet('f', 'u', 'n')
cs: scala.collection.immutable.TreeSet[Char] = TreeSet(f, n, u)

//And here are a few TreeMap examples:

scala> var tm = TreeMap(3 -> 'x', 1 -> 'x', 4 -> 'x')
tm: scala.collection.immutable.TreeMap[Int,Char]= Map(1 -> x, 3 -> x, 4 -> x)

scala> tm += (2 -> 'x')
scala> tm
res30: scala.collection.immutable.TreeMap[Int,Char]= Map(1 -> x, 2 -> x, 3 -> x, 4 -> x)
Selecting mutable versus immutable collections
When in doubt, it is better to start with an immutable collection and change it later if you need to, because immutable collections can be easier to reason about than mutable ones.
Besides being potentially easier to reason about, immutable collections can usually be stored more compactly than mutable ones if the number of el- ements stored in the collection is small. For instance an empty mutable map in its default representation of HashMap takes up about 80 bytes and about 16 more are added for each entry that’s added to it. An empty immutable Map is a single object that’s shared between all references, so referring to it es- sentially costs just a single pointer field. What’s more, the Scala collections library currently stores immutable maps and sets with up to four entries in a single object, which typically takes up between 16 and 40 bytes, depending on the number of entries stored in the collection.4 So for small maps and sets, the immutable versions are much more compact than the mutable ones.
Initialise a collection with another collection
 
You need to create an empty TreeSet and pass elements of the set to it:
scala> val colors = Set(“blue”, “red”, “green")
scala> val orderedColors = TreeSet[String]() ++ colors
treeSet: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red)
Tuples
A tuple combines a fixed number of items together so that they can be passed around as a whole. Unlike an array or list, a tuple can hold objects with different types. Here is an example of a tuple holding an integer, a string, and the console:
(1, "hello", Console)
A common application of tuples is returning multiple values from a method. For example:
def longestWord(words: Array[String]) = {
     var word = words(0)
     var index = 0

     for (i <- 1 to words.length) {
          if (words(i).length > word.length) {
               word = words(i)
               index = i
          }
     }

     (word, index)
}

scala> val (word, index) = longestWord(“The quick brown fox”.split(“ “))
scala> println(s”longest word is $word with index of $index”)
>> longest word is quick with index of 1 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s