# 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)
```
