Scala collection

Download Scala collection

Post on 15-Jan-2015




2 download

Embed Size (px)




<ul><li> 1. Introducing Collectionsin ScalaRishi KhandelwalSoftware ConsultantKnoldus Software LLPEmail :</li></ul><p> 2. FeaturesEasy to useConciseSafeFastUniversal 3. Continued...e.g. val (minors, adults) = people partition (_.age &lt; 18) It partitions a collection of people into minors and adults depending on their age.Much more concise than the one to three loops required for traditionalcollection processing.Writing this code is much easier, once we learn the basiccollection vocabulary.Safer than writing explicit loops.The partition operation is quite fast. 4. Mutable and Immutable collectionsMutable :can change, add, or remove elements of a collectionimport scala.collection.mutableImmutable :never changeupdation return a new collection and leave the old collectionunchanged.By default collections are immutable 5. Continued...To use mutable collections, just importscala.collection.mutable.To use both mutable and immutable versions of collections isto import just the package collection.mutable.e.g. scala&gt; import scala.collection.mutable import scala.collection.mutable scala&gt; val immutSet=Set(1,2,3) immutSet: scala.collection.immutable.Set[Int] = Set(1, 2, 3) scala&gt; val mutSet=mutable.Set(1,2,3) mutSet: scala.collection.mutable.Set[Int] = Set(2, 1, 3) 6. Collections consistencyQuite a bit of commonality shared by all these collections.Every kind of collection can be created by the same uniformsyntax writing collection class name followed by its elements:e.g. Traversable(1, 2, 3) Iterable("x", "y", "z") Map("x" -&gt; 24, "y" -&gt; 25, "z" -&gt; 26) Set(Color.Red, Color.Green, Color.Blue)Same principle also applies for specific collection implementationse.g. List(1, 2, 3) HashMap("x" -&gt; 24, "y" -&gt; 25, "z" -&gt; 26) 7. Collection hierarchyscala Traversable trait scala Iterable trait scala scala.collection scala.collectionSeqSetMaptraittraittrait 8. Trait TraversableAt the top of the collection hierarchy.Only abstract operation is foreach:def foreach[U](f: Elem =&gt;U)foreach method is meant to traverse all elements of the collection.apply the given operation f, to each element.Elem =&gt; U= the type of the operation.Elem = the type of the collections elements.U = an arbitrary result type.It also defines many concrete methods 9. Trait IterableNext trait from the top.All methods are defined in terms of an abstract method, iterator, whichyields the collections elements one by one.Implementation of foreach :def foreach[U](f: Elem =&gt; U): Unit = { val it = iterator while (it.hasNext) f(}Two more methods exist in Iterable that return iterators:grouped and sliding.These iterators do not return single elements but whole subsequences ofelements of the original collection. 10. scala&gt; val xs = List(1, 2, 3, 4, 5)xs: List[Int] = List(1, 2, 3, 4, 5)grouped :scala&gt; val git = xs grouped 3git: Iterator[List[Int]] = non-empty iteratorscala&gt; List[Int] = List(1, 2, 3)scala&gt; List[Int] = List(4, 5)sliding:scala&gt; val sit = xs sliding 3sit: Iterator[List[Int]] = non-empty iteratorscala&gt; List[Int] = List(1, 2, 3)scala&gt; List[Int] = List(2, 3, 4)scala&gt; List[Int] = List(3, 4, 5) 11. Why have both Traversable and Iterable?sealed abstract class Treecase class Branch(left: Tree, right: Tree) extends Treecase class Node(elem: Int) extends Tree Using Traversablesealed abstract class Tree extends Traversable[Int] {def foreach[U](f: Int =&gt; U) = this match {case Node(elem) =&gt; f(elem)case Branch(l, r) =&gt; l foreach f; r foreach f}}Traversing a balanced tree takes time proportional to the number ofelements in the tree. A balanced tree with N leaves will have N - 1 interior nodes ofclass branch. So the total number of steps to traverse the tree is N + N - 1. 12. Continued...Using Iterable :sealed abstract class Tree extends Iterable[Int] {def iterator: Iterator[Int] = this match { case Node(elem) =&gt; Iterator.single(elem) case Branch(l, r) =&gt; l.iterator ++ r.iterator } } Theres an efficiency problem that has to do with the implementation of theiterator concatenation method, ++The computation needs to follow one indirection to get at the right iterator(either l.iterator,or r.iterator).Overall, that makes log(N) indirections to get at a leaf of a balanced treewith N leaves. 13. Trait SeqSeq trait represents sequences.A sequence is a kind of iterable that has a length and whose elements havefixed index positions, starting from 0.Each Seq trait has two subtraits, LinearSeq and IndexedSeqA linear sequence has efficient head and tail operationse.g. List, StreamAn indexed sequence has efficient apply, length, and (if mutable)update operations. e.g. Array, ArrayBuffer 14. SequencesClasses that inherit from trait SeqLists :Always Immutable Support fast addition and removal of items to the beginning ofthe listscala&gt; val colors = List("red", "blue", "green")colors: List[java.lang.String] = List(red, blue, green)scala&gt; colors.headres0: java.lang.String = redscala&gt; colors.tailres1: List[java.lang.String] = List(blue, green) 15. Continued...Array :Efficiently access an element at an arbitrary position.Scala arrays are represented in the same way as Java arraysCreate an array whose size is known but dont yet know theelement values:e.g. scala&gt; val fiveInts = new Array[Int](5) fiveInts: Array[Int] = Array(0, 0, 0, 0, 0)Initialize an array when we do know the element values:e.g. scala&gt; val fiveToOne = Array(5, 4, 3, 2, 1)fiveToOne: Array[Int] = Array(5, 4, 3, 2, 1)Accessing and updating an array element:e.g. scala&gt; fiveInts(0) = fiveToOne(4) scala&gt; fiveInts res1: Array[Int] = Array(1, 0, 0, 0, 0) 16. Continued...List buffers :It is a mutable object which can help you build lists moreefficiently when you need to append.Provides constant time append and prepend operations.Append elements with the += operator,and prepend them withthe +: operator.Obtain a List by invoking toList on the ListBuffer.To use it, just import scala.collection.mutable.ListBuffer 17. Continued...scala&gt; import scala.collection.mutable.ListBufferimport scala.collection.mutable.ListBufferscala&gt; val buf = new ListBuffer[Int]buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()scala&gt; buf += 1scala&gt; buf += 2scala&gt; bufres11: scala.collection.mutable.ListBuffer[Int]= ListBuffer(1, 2)scala&gt; 3 +: bufres12: scala.collection.mutable.Buffer[Int]= ListBuffer(3, 1, 2)scala&gt; buf.toListres13: List[Int] = List(3, 1, 2) 18. Continued...Array buffers : It is like an array, except that you can additionally add and removeelements from the beginning and end of the sequence. To use it just import scala.collection.mutable.ArrayBuffer e.g. scala&gt; import scala.collection.mutable.ArrayBufferimport scala.collection.mutable.ArrayBuffer To create an ArrayBuffer, only specify a type parameter, no need not specify a length. e.g. scala&gt; val buf = new ArrayBuffer[Int]()buf: scala.collection.mutable.ArrayBuffer[Int] =ArrayBuffer() 19. Continued... Append to an ArrayBuffer using the += method:e.g. scala&gt; buf += 12 scala&gt; buf += 15 scala&gt; buf res16: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(12, 15). All the normal array methods are availablee.g. scala&gt; buf.length res17: Int = 2 scala&gt; buf(0) res18: Int = 12 20. Continued... Queue : first-in-first-out sequence. Both mutable and immutable variants of Queue. Create an empty immutable queue: e.g. scala&gt; import scala.collection.immutable.Queueimport scala.collection.immutable.Queuescala&gt; val empty = Queue[Int]()empty: scala.collection.immutable.Queue[Int] = Queue() Note : scala&gt; val empty=new Queue[Int] :8: error: constructor Queue in class Queue cannot be accessed in object $iw Access to protected constructor Queue not permitted because enclosing class object $iw in object $iw is not a subclass ofclass Queue in package immutable where target is defined val empty=new Queue[Int] ^ 21. Continued...Append an element to an immutable queue with enqueue:e.g. scala&gt; val has1 = empty.enqueue(1) has1: scala.collection.immutable.Queue[Int] = Queue(1)To append multiple elements to a queue, call enqueue with a collection asits argument:e.g. scala&gt; val has123 = has1.enqueue(List(2, 3))has123: scala.collection.immutable.Queue[Int] =Queue(1,2,3)To remove an element from the head of the queue,use dequeue:scala&gt; val (element, has23) = has123.dequeueelement: Int = 1has23: scala.collection.immutable.Queue[Int] = Queue(2,3) 22. Continued...Use mutable Queuescala&gt; import scala.collection.mutable.Queueimport scala.collection.mutable.Queuescala&gt; val queue = new Queue[String]queue: scala.collection.mutable.Queue[String] = Queue()scala&gt; queue += "a"scala&gt; queue ++= List("b", "c")scala&gt; queueres21: scala.collection.mutable.Queue[String] = Queue(a, b, c)scala&gt; queue.dequeueres22: String = ascala&gt; queueres23: scala.collection.mutable.Queue[String] = Queue(b, c) 23. Continued...Stack :last-in-first-out sequence.Both mutable and immutable variants..push an element onto a stack with push,pop an element with pop,peek at the top of the stack without removing it with topscala&gt; import scala.collection.mutable.Stackimport scala.collection.mutable.Stackscala&gt; val stack = new Stack[Int]stack: scala.collection.mutable.Stack[Int] = Stack() 24. Continued...scala&gt; stack.push(1)scala&gt; stackres1: scala.collection.mutable.Stack[Int] = Stack(1)scala&gt; stack.push(2)scala&gt; stackres3: scala.collection.mutable.Stack[Int] = Stack(1, 2)scala&gt; stack.topres8: Int = 2scala&gt; stackres9: scala.collection.mutable.Stack[Int] = Stack(1, 2)scala&gt; stack.popres10: Int = 2scala&gt; stackres11: scala.collection.mutable.Stack[Int] = Stack(1) 25. Continued...Strings (via StringOps) :It implements many sequence methods..Predef has an implicit conversion from String to StringOps,we can treat anystring as a Seq[Char].scala&gt; def hasUpperCase(s: String) = s.exists(_.isUpperCase)hasUpperCase: (String)Booleanscala&gt; hasUpperCase("Robert Frost")res14: Boolean = truescala&gt; hasUpperCase("e e cummings")res15: Boolean = false 26. Trait SetSets are Iterables that contain no duplicate elementsBoth mutable and immutablescala.collection Set traitscala.collection.immutable scala.collection.mutable SetSet traittraitscala.collection.immutable Scala.collection.mutableHashSetHashSet 27. Continued...scala&gt; val text = "See Spot run. Run, Spot. Run!"text: java.lang.String = See Spot run. Run, Spot. Run!scala&gt; val wordsArray = text.split("[ !,.]+")wordsArray: Array[java.lang.String] =Array(See, Spot, run, Run, Spot, Run)scala&gt; import scala.collection.mutableimport scala.collection.mutablescala&gt;val words = mutable.Set.empty[String]words: scala.collection.mutable.Set[String] = Set()scala&gt; for (word wordsres25: scala.collection.mutable.Set[String] = Set(spot, run, see) 28. Continued...Two Set subtraits are SortedSet and BitSetSortedSet :No matter what order elements were added to the set, the elements aretraversed in sorted order.Default representation of a SortedSet is an ordered binary treeDefine ordering :scala&gt; val myOrdering = Ordering.fromLessThan[String](_ &gt; _)myOrdering: scala.math.Ordering[String] = ...Create an empty tree set with that ordering, use:scala&gt; import scala.collection.immutable.TreeSetimport scala.collection.immutable.TreeSetscala&gt; val mySet=TreeSet.empty(myOrdering)mySet: scala.collection.immutable.TreeSet[String] = TreeSet() 29. Continued...Default ordering Set :scala&gt; val set = TreeSet.empty[String]set: scala.collection.immutable.TreeSet[String] = TreeSet()Creating new sets from a tree set by concatenationscala&gt; val numbers = set + ("one", "two", "three", "four")numbers: scala.collection.immutable.TreeSet[String] =TreeSet(four, one,three, two)scala&gt; val myNumbers=mySet + ("one","two","three","four")myNumbers: scala.collection.immutable.TreeSet[String] = TreeSet(two,three, one, four)Sorted sets also support ranges of elements.scala&gt; numbers range ("one", "two")res13: scala.collection.immutable.TreeSet[String]= TreeSet(one, three)scala&gt; numbers from "three"res14: scala.collection.immutable.TreeSet[String] = TreeSet(three, two) 30. Continued...Bit Set :Bit sets are sets of non-negative integer elements that are implemented inone or more words of packed bits.The internal representation of a bit set uses an array of Longs.The first Long covers elements from 0 to 63, the second from 64 to 127, andso onFor every Long, each of its 64 bits is set to 1 if the corresponding element iscontained in the set, and is unset otherwise.It follows that the size of a bit set depends on the largest integer thatsstored in it. If N is that largest integer, then the size of the set is N/64 Longwords,or N/8 bytes, plus a small number of extra bytes for statusinformation. 31. Trait MapMaps are Iterables of pairs of keys and values.Both mutable and immutablescala.collectionMap traitscala.collection.immutable scala.collection.mutableMapMap traittraitscala.collection.immutable Scala.collection.mutable HashMapHashMap 32. Continued...scala&gt; import scala.collection.mutableimport scala.collection.mutablescala&gt; val map = mutable.Map.empty[String, Int]map: scala.collection.mutable.Map[String,Int] = Map()scala&gt; map("hello") = 1scala&gt; map("there") = 2scala&gt; mapres2: scala.collection.mutable.Map[String,Int] = Map(there -&gt; 2, hello -&gt; 1)scala&gt; map("hello")res3: Int = 1 33. Continued...Sorted MapTrait SortedMap are implemented by class TreeMapOrder is determined by Ordered trait on key element typescala&gt; import scala.collection.immutable.TreeMapimport scala.collection.immutable.TreeMapscala&gt; var tm = TreeMap(3 -&gt; x, 1 -&gt; x, 4 -&gt; x)tm: scala.collection.immutable.SortedMap[Int,Char] =Map(1 -&gt; x, 3 -&gt; x, 4 -&gt; x)scala&gt; tm += (2 -&gt; x)scala&gt; tmres38: scala.collection.immutable.SortedMap[Int,Char] =Map(1 -&gt; x, 2 -&gt; x, 3 -&gt; x, 4 -&gt; x) 34. Default sets and mapsscala.collection.mutable.Set() factory returns ascala.collection.mutable.HashSetSimilarly, the scala.collection.mutable.Map() factory returns ascala.collection.mutable.HashMap.The class returned by the scala.collection.immutable.Set() factory method&amp; scala.collection.immutable.Map() depends on how many elements youpass to itNumber of elementsImplementation 0 scala.collection.immutable.EmptySet 1 scala.collection.immutable.Set1 2 scala.collection.immutable.Set2 3 scala.collection.immutable.Set3 4 scala.collection.immutable.Set45 or morescala.collection.immutable.HashSet 35. Continued...Similarily for MapNumber of elements Implementation 0 scala.collection.immutable.EmptyMap 1 scala.collection.immutable.Map1 2 scala.collection.immutable.Map2 3 scala.collection.immutable.Map3 4 scala.collection.immutable.Map45 or morescala.collection.immutable.HashMap 36. Synchronized sets and mapsFor a thread-safe map,mix the SynchronizedMap trait into particular mapimplementation import scala.collection.mutable.{Map,SynchronizedMap, HashMap} object MapMaker {def makeMap: Map[String, String] = { new HashMap[String, String] with SynchronizedMap[String, String] { override def default(key: String) =Why do you want to know...</p>