# 8. \[Exercise] Data Structures in Scala

## Activity

* For this activity, go ahead and import from the resource the file LearningScala4.scala
* Scala contains Tuples which are immutable lists
* Tuples can be used for database fields or passing entire rows of data

  ```
    // Data structures
    // Tuples (Also really common with Spark!!)
    // Immutable lists
    // Often thought of as database fields, or columns.
    // Useful for passing around entire rows of data.

    val captainStuff = ("Picard", "Enterprise-D", "NCC-1701-D")
    //> captainStuff  : (String, String, String) = (Picard,Enterprise-D,NCC-1701-D)

    println(captainStuff)                           
    //> (Picard,Enterprise-D,NCC-1701-D)

      // You refer to individual fields with their ONE-BASED index:
      println(captainStuff._1)                        
      //> Picard
      println(captainStuff._2)                        
      //> Enterprise-D
      println(captainStuff._3)                        
      //> NCC-1701-D
  ```
* You can create key/value with -> and also mixing diffeent type in a tuple

  ```
    // You can create a key/value pair with ->

    val picardsShip = "Picard" -> "Enterprise-D"
    //> picardsShip  : (String, String) = (Picard,Enterprise-D)
    println(picardsShip._2)                          
    //> Enterprise-D

    // You can mix different types in a tuple

    val aBunchOfStuff = ("Kirk", 1964, true)         
    //> aBunchOfStuff  : (String, Int, Boolean) = (Kirk,1964,true)
  ```
* You can create a List in Scala which holds more functionality than a tuple

  ```
    // Lists
    // Like a tuple, but it's an actual Collection object that has more functionality.
    // Also, it cannot hold items of different types.
    // It's a singly-linked list under the hood.

    val shipList = List("Enterprise", "Defiant", "Voyager", "Deep Space Nine")
    //> shipList  : List[String] = List(Enterprise, Defiant, Voyager, Deep Space Nine)

    // Access individual members using () with ZERO-BASED index (confused yet?)
    println(shipList(1))                             
    //> Defiant

    // head and tail give you the first item, and the remaining ones.
    println(shipList.head)                           
    //> Enterprise
    println(shipList.tail)                           
    //> List(Defiant, Voyager, Deep Space Nine)

    // Iterating though a list
    for (ship <- shipList) {println(ship)}           
    //> Enterprise
    //| Defiant
    //| Voyager
    //| Deep Space Nine
  ```
* You can also apply function literal to a list in Scala

  ```
    // Let's apply a function literal to a list! map() can be used to apply any function to every item in a collection.

    val backwardShips = shipList.map( (ship: String) => {ship.reverse})
    //> backwardShips  : List[String] = List(esirpretnE, tnaifeD, regayoV, eniN ecapS peeD)

    for (ship <- backwardShips) {println(ship)}      
    //> esirpretnE
    //| tnaifeD
    //| regayoV
    //| eniN ecapS peeD

    // reduce() can be used to combine together all the items in a collection using some function.
    val numberList = List(1, 2, 3, 4, 5)              
    //> numberList  : List[Int] = List(1, 2, 3, 4, 5)

    val sum = numberList.reduce( (x: Int, y: Int) => x + y)
    //> sum  : Int = 15
    println(sum)                                      
    //> 15

    // filter() can remove stuff you don't want. Here we'll introduce wildcard syntax while we're at it.
    val iHateFives = numberList.filter( (x: Int) => x != 5)
    //> iHateFives  : List[Int] = List(1, 2, 3, 4)

    val iHateThrees = numberList.filter(_ != 3)       
    //> iHateThrees  : List[Int] = List(1, 2, 4, 5)
  ```
* You can use more functions with Lists in Scala

  ```
    // Note that Spark has its own map, reduce, and filter functions that can distribute these operations. But they work the same way!
    // Also, you understand MapReduce now :)

    // Concatenating lists
    val moreNumbers = List(6, 7, 8)                   
    //> moreNumbers  : List[Int] = List(6, 7, 8)

    val lotsOfNumbers = numberList ++ moreNumbers     
    //> lotsOfNumbers  : List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)

    // More list fun
    val reversed = numberList.reverse                 
    //> reversed  : List[Int] = List(5, 4, 3, 2, 1)

    val sorted = reversed.sorted                      
    //> sorted  : List[Int] = List(1, 2, 3, 4, 5)

    val lotsOfDuplicates = numberList ++ numberList   
    //> lotsOfDuplicates  : List[Int] = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)

    val distinctValues = lotsOfDuplicates.distinct    
    //> distinctValues  : List[Int] = List(1, 2, 3, 4, 5)

    val maxValue = numberList.max                     
    //> maxValue  : Int = 5

    val total = numberList.sum                        
    //> total  : Int = 15

    val hasThree = iHateThrees.contains(3)            
    //> hasThree  : Boolean = false
  ```
* You can also use Maps in Scala

  ```
    // Maps
    // Useful for key/value lookups on distinct keys
    // Like dictionaries in other languages

    val shipMap = Map("Kirk" -> "Enterprise", "Picard" -> "Enterprise-D", "Sisko" -> "Deep Space Nine", "Janeway" -> "Voyager")
    //> shipMap  : scala.collection.immutable.Map[String,String] = Map(Kirk -> Enterprise, 
    //| Picard -> Enterprise-D, Sisko -> Deep Space Nine, Janeway -> Voyager)

    println(shipMap("Janeway"))                       
    //> Voyager

    // Dealing with missing keys
    println(shipMap.contains("Archer"))               
    //> false

    val archersShip = util.Try(shipMap("Archer")) getOrElse "Unknown"
    //> archersShip  : String = Unknown

    println(archersShip)                              
    //> Unknown
  ```

## Exercise

```
    // EXERCISE
    // Create a list of the numbers 1-20; your job is to print out numbers that are evenly divisible by three. (Scala's
    // modula operator, like other languages, is %, which gives you the remainder after division. For example, 9 % 3 = 0
    // because 9 is evenly divisible by 3.) Do this first by iterating through all the items in the list and testing each
    // one as you go. Then, do it again by using a filter function on the list instead.

    // That's enough for now!
    // There is MUCH more to learn about Scala. We didn't cover many other collection types, including mutable collections.
    // And we didn't even touch on object-oriented Scala. The book "Learning Scala" from O'Reilly is great if you want to
    // go into more depth - but you've got enough to get through this course for now.

    val numbersList = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
    //> numbersList  : List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)

    for (currentNumber <- numbersList) {if(currentNumber % 3 == 0){println(currentNumber)}}
    //> 3
    //| 6
    //| 9
    //| 12
    //| 15
    //| 18

    val filteredList = numbersList.filter(_ %3 == 0)  
    //> filteredList  : List[Int] = List(3, 6, 9, 12, 15, 18)
    println(filteredList)                             
    //> List(3, 6, 9, 12, 15, 18)
```
