Scala (9): Collection and Functional Combinators

Collection

List

val number = List(1, 2, 3, 4) 
// output: List[Int] = List(1, 2, 3, 4)

Set: no duplicates

val tempSet = Set(1, 1, 2) 
// output: scala.collection.immutable.Set[Int] = Set(1, 2)

Tuple

Without class, tuple can help collect different types to build a logical collection without using a class. Tuple can use position to get object, which is based on 1.

val hostPort = ("localhost", 80) // output: (String, Int) = ("localhost", 80)
hostPort._1 // output: String = localhost
hostPort._2 // output: Int = 80

Tuple can well connect with pattern matching.

hostPort match {
  case ("localhost", port) => println(port)
  case (host, port) => println(host + port)
}

When you want to create two elements by tuple, you can use special syntax: ->

1 -> 2 // output: (Int, Int) = (1, 2)

Map

Map can map a key to a value; this value can be any types: standard type, function. Map can be thoughts of as a list of paris. Note: map method is really like to create two elements by tuple, so Map(1 -> “one”, 2 -> “two”) can be changed to Map((1, “one”), (2, “two”)).

Map(1 -> 2)
Map("foo" -> "bar")
Map(1 -> Map("foo" -> "bar"))
Map("timesTwo" -> { timesTwo(_) })

Here is the word count example by map.

val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")

def wordcount(str: String): Int = str.split(" ").count("msg" == _)

val num = file.map(wordcount).reduceLeft(_ + _)

println("wordcount:" + num) // output: wordcount:4

Option

Option is a container, which is generic. It has two sub-class, one is Some[T], the other is None. You see its interface and will know everything.

trait Option[T] {
  def isDefined: Boolean
  def get: T
  def getOrElse(t: T): T
}

Map.get uses Option as return value.

val numbers = Map(1 -> "one", 2 -> "two")
numbers.get(2) // res0: Option[String] = Some(two)
numbers.get(3) // res1: Option[String] = None

We can use getOrElse or pattern matching to get the real result.

res0.getOrElse(0) // output: Any = two
val result = res0 match {
  case Some(n) => n
  case None => 0
}
// output: Any = two

Functional Combinators

map

map will apply each element to one function and return element to a new List.

numbers.map((i: Int) => i * 2)

Or pass a partial function to map

def timesTwo(i: Int): Int = i * 2
numbers.map(timesTwo _) //output: List(2,4,6)

foreach

foreach is similar to map, but no return value.  foreach is only used in the function which has side-effect( different threads might modify same objects resource at the same time).

numbers.foreach((i: Int) => i * 2) //output: 
val doubled = numbers.foreach((i: Int) => i * 2) // doubled: Unit = ()

filter

filter will remove any element which makes the return value of the function to be false. If a function returns a Boolean, we call the function Judgement/predicate Function.

numbers.filter((i: Int) => i % 2 == 0)
def isEven(i: Int): Boolean = i % 2 == 0
numbers.filter(isEven _)
case class PhoneExt(name: String, ext: Int)
val extensions = List(PhoneExt("steve", 100), PhoneExt("robey", 200))
extensions.filter{ case PhoneExt(name, extension) => extension < 200} 
// output: List(PhoneExt(steve, 100))

zip

zip will merge two Lists’ contents to a single list of pairs.

List(1, 2, 3).zip(List("a", "b", "c"))
// output: List[(Int, String)] = List((1, a), (2, b), (3, c))

partition

partition will partition List according to given function.

val numbers = List(1, 2, 3, 4, 5, 6)
numbers.partition(_ % 2 == 0)
// output: (List[Int], List[Int]) = (List(2, 4, 6), List(1, 3, 5))

find

find will return the first element which satisfies the judgement function. Note: find return’s type is Option.

numbers.find((i: Int) => i > 5)
// output: Option[Int] = Some(6)

drop & dropWhile

drop will delete first i elements.

numbers.drop(5) // output: List(6)

dropWhile will delete elements until it finds the element which satisfies the judgement function.

numbers.dropWhile(_ % 2 != 0)
// output: List[Int] = List(2, 3, 4, 5, 6)

foldLeft & foldRight

numbers.foldLeft(0)((m: Int, n: Int) => m + n)
// 0 is the initial value, m is the calculator
// m: 0 n: 1
// m: 1 n: 2
// m: 3 n: 3
// m: 6 n: 4
// m: 10 n: 5
// m: 15 n: 6
numbers.foldRight(0)((m: Int, n: Int) => m + n)
// 0 is the initial value, n is the calculator
// m: 6 n: 0
// m: 5 n: 6
// m: 4 n: 11
// m: 3 n: 15
// m: 2 n: 18
// m: 1 n: 20

flatten

flatten is to transfer nested structure to flat hierarchy collection, which collapses one level of nested structure.

List(List(1, 2), List(3, 4)).flatten
// output: List(1, 2, 3, 4)

flatMap

flatMap combines mapping and flattening together, which needs a function to deal with nested structure and concatenates together.

val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers.flatMap(x => x.map(_ * 2)) // output: List(2, 4, 6, 8)
nestedNumbers.map((x: List[Int]) => x.map(_ * 2)).flatten // output: List(2, 4, 6, 8)

compose & andThen

compose and andThen will combine two functions together. The difference between the two is the order.

def f(s: String) = "hello" + s
def g(s: String) = "world" + s
val fComposeG = f _ compose g _
fComposeG("yeah") // output: f(g(yeah))
val fAndThenG = f _ andThen g _
fAndThenG("yeah") // output: g(f(yeah))
Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s