Hi. This section is about extra things on collections. The collection framework is very large. We've covered just the most important things so far. In these optional slides, we're going to go into a bit more detail on the stuff we skipped over. The structure of this material will follow the same structure we used before. We're going to look at ways to construct collections, then to query them, and then to transform them. As this is optional material and there is quite a lot to get through, we're going to go through it fairly quickly. If you're confused at any point or want to go into more detail, I encourage you to pause the slides and try the code samples on your own. One way we can construct a collection is by joining together or concatenating two existing collections. The method that does this is written as plus plus as shown on the slides. We can do this with any collection type, list, array buffers, maps, it doesn't matter. Give it a try yourself and see how it works. On the previous slides, when we call the plus plus method, we used operator style which means no dot and spaces around the method name. As with all methods in scala, we can also call it using the dot notation if we prefer. That's shown here on the slide. Note that when we concatenate collections, the original collections are not modified. The operation is immutable if we like. This is the case for many operations in the collection library. Any method that works on both, mutable and immutable collections, works the same way on both and will not modify the original collection. For mutable collections such as array buffer, there is a method which will perform a mutable concatenation. The original sequence, the one in which we call the method is changed after calling it. This method is written plus plus equals as shown on the slide. The second sequence, the parameter we pass to plus plus equal is unchanged after calling this method. Mutable sequences such as array buffer, have additional methods to prepend or append elements in a mutable way. This is the plus equal method. It modifies the original collection, adding the element as shown on the slides. We can also mutably remove elements. That's the minus equal method. It removes the first element which is equal to the given parameter. There is also the minus minus equal method which removes all the elements that are found in another collection. This other collection does not have to be mutable. Note that all of these symbolic names like plus equal and plus plus, have alphabetic equivalents. The equivalent are shown on the slide here. You can use whichever you prefer. I find that in practice, people are generally comfortable using the symbolic methods but it's not a big deal if you don't like using them. We've talked a lot about methods that are only available on mutable collections and you may be thinking which should we use, mutable or immutable? It seems that mutable collections have additional operations available so maybe we should prefer them. Our advice is to use the immutable collections in all cases, unless you specifically require a mutable collection, in which case a mutable collection is fine. To summarize what we've seen about constructing collections, we have seen plus plus to append together or concatenate collections. And some of the methods that are available just on mutable collections plus equals, plus plus equals, minus equals and minus minus equals. We're now going to move on to querying collections. On this slide we're going to look at two methods. Exists, which tells it is at least one element of the collection matches, predicate and for all, which tells us if all of the elements match a predicate. We have some examples on the slide. Both methods take a predicate, which is a function that takes in an element and returns true or false. When we have a sequence, we can access elements by index, by calling the sequence as if it was a function. Two things to remember about this, the first is that indexes start at zero. Index 0 is the first element. And the second thing, is that calling something as if it was a function is calling the apply method on that object. To reiterate that point, remember that calling a function is calling the apply method on an object and that's a general shorthand in scala. Anything that you can call as if it was a function is in fact rewritten into calling the apply method. In summary, we have seen the following methods for querying properties of a collection. We can use forall to check if all of the elements match a predicate. And we can use exists to check if at least one element matters a predicate. We've also seen how to access elements of a sequence by index. We're now going to look at how we can reason about transformations. When first encountering map, flatMap and foldLeft, it can be difficult to choose between them, if we look at the types, at algebraic equations, that can help us to reason about when we should use each of these methods. Let's start by looking at the type equation for map. We have F[A] where F is the container type such as list or array buffer and A is the type of elements within the container, such as Int or String. We call map with an A to B function. So transforming elements from one type A to another type B, then the result is F[B]. This tells us that the container type list or array buffer or whatever, stays the same but the element type changes. We can use the type equation to reason about uses of map. So say for example, we have a list of int, a function from int to string and we want to produce a list of string. If we substitute these into the type equation, then it would tell us that map is the correct method to call to achieve the result we're after. We can write a similar type equation for flatMap. It differs from map in that the function we pass to flatMap has typed A to F[B] instead of A to B. And we can use this to distinguish between the behavior of map and flatMap. Let's say we have a list of integer, a function from int to list string. The type equation tells us that if we call flatMap in this case will end up with a list of string. If we were to use map however, would end up with a list of list of string. The correct function to call depends on the result we're trying to achieve. If we wanted the list of string, then flatMap is the correct method. Let's now look at the type equation for foldLeft. This is quite different from flatMap and map. We have on the left hand side as usual, the type F[A], where F is the container and A is the element type. However, the parameters to foldLeft are of type B, which is the initial value of the accumulator and the combining function which has type B and A to B, B being the accumulator, A being the element. And the result is just of type B. There's no container here necessarily. This tells us that foldLeft is much more general than map and flatMap. Let's look at some of the other ways in which we can use these type equations to reason algebraically about which method we should use. If the input has type F[A] and the output has type F[B], then this tells us we should be looking at map and flatMap before we look at foldLeft. If the output does not have the same F collection type as the input, then we have to use foldLeft because map and flatMap always keep that collection type around in the output. We can use the type of the transformation function to choose between map and flatMap. Do we transform into the same collection type A to F[B], which we would use flatMap or do we have an A to B function, which we would use with map. In summary, we've looked at the type equations which are algebraic equations like we might have used in high school, which specified the types of the inputs to map, flatMap, and foldLeft and the result we get from them. We can use these type equations to reason about when we should use each method and what are the parameters we should provide to them. We're now going to look at some of the other collection types that are available in the collections library. One of these are mutable maps which are in the mutable package just like array buffer. With a mutable map, you can mutably update it, which means you don't create a new collection when you add elements. There's an example on the slide using a hash map from the mutable package. Now let's look at some of the other collections that are available in the collections library. A set is a collection that only contains one instance of a given element. A bit set is a special type of set. It's mutable and it only stores bits which means it can store information in a very limited amount of memory if we can get away with just using bits. And the lazy list is a type of sequence that could have an infinite length. These are all fairly specialized collections which we don't use in day to day programming, but when you need them they are extremely useful. And that completes our overview of some of the additional things in the collections library. To recap, we've seen concatenate in collections using plus plus, operations on multiple collections, querying using forall and exists, accessing elements by index, reasoning using type equations and some of the other collection types, like set and bit set.