전 시간 질문


In [1]:
def runLength[A](l: List[A]): List[(A, Int)] = l.foldLeft(List.empty[(A, Int)]){
  case ((x, n) :: xs, a) if x == a => {
    println("(x : " + x + ", n+1 : " + n+1 + ") :: xs : " + xs)
    (x, n+1) :: xs
  }
  case (acc, a) => {
    println("(a : " + a + ", 1) :: acc : " + acc)
    (a,1) :: acc
  }
}.reverse

println("abbbcc".toList)
println(runLength("abbbcc".toList))


List(a, b, b, b, c, c)
(a : a, 1) :: acc : List()
(a : b, 1) :: acc : List((a,1))
(x : b, n+1 : 11) :: xs : List((a,1))
(x : b, n+1 : 21) :: xs : List((a,1))
(a : c, 1) :: acc : List((b,3), (a,1))
(x : c, n+1 : 11) :: xs : List((b,3), (a,1))
List((a,1), (b,3), (c,2))
Out[1]:
defined function runLength

In [2]:
def runLength[A](l: List[A]): List[(A, Int)] = l.foldLeft(List.empty[(A, Int)]){
 case ((x, n) :: xs, a) if x == a =>
   println(s"${(x,n)::xs}* , $a")
   (x, n + 1) :: xs
 case (acc, a) =>
   println(s"$acc, $a")
   (a, 1) :: acc
}.reverse

println(runLength("abbbcc".toList))
println("Ok!")


List(), a
List((a,1)), b
List((b,1), (a,1))* , b
List((b,2), (a,1))* , b
List((b,3), (a,1)), c
List((c,1), (b,3), (a,1))* , c
List((a,1), (b,3), (c,2))
Ok!
Out[2]:
defined function runLength

Exercise : FIZZBUZZ


In [ ]:
def fizzBuzz(n: Int)(cond: (Int, String)*): Unit = ???

In [5]:
def fizzBuzz(n: Int)(cond: (Int, String)*): Unit = 1 to n map { i => 
    cond.foldLeft(""){ case (acc, (x, s)) => if (i % x == 0) acc + s else acc } match {
        case "" => i.toString
        case other => other
    } 
} foreach println

fizzBuzz(20)((3, "Fizz"), (5, "Buzz"))
println("OK")


1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
OK
Out[5]:
defined function fizzBuzz

Collection Library 2

For Comprehensions


In [6]:
Seq(1, 2, 3).map(_ * 2)


Out[6]:
res5: Seq[Int] = List(2, 4, 6)

In [7]:
// For Comprehensions 표현
for {
    x <- Seq(1, 2, 3)
} yield x * 2


Out[7]:
res6: Seq[Int] = List(2, 4, 6)

FlatMAP


In [8]:
val data = Seq(Seq(1), Seq(2, 3), Seq(4, 5, 6))


Out[8]:
data: Seq[Seq[Int]] = List(List(1), List(2, 3), List(4, 5, 6))

In [9]:
data.flatMap(_.map(_ * 2))


Out[9]:
res8: Seq[Int] = List(2, 4, 6, 8, 10, 12)

In [11]:
// For Comprehensions 표현
for {
    subseq <- data
    element <- subseq
} yield element * 2


Out[11]:
res10: Seq[Int] = List(2, 4, 6, 8, 10, 12)

In [15]:
a.flatMap(x => b.flatMap(y => c.map(z => e)))

In [ ]:
for(x <-a ; y <- b; z <- c) yield e

In [12]:
for { x <- Seq(-2, -1, 0, 1, 2) if x > 0 } yield x


Out[12]:
res11: Seq[Int] = List(1, 2)

ZIP


In [13]:
Seq(1, 2, 3) zip Seq(4, 5, 6)


Out[13]:
res12: Seq[(Int, Int)] = List((1, 4), (2, 5), (3, 6))

In [14]:
for{
  (x, y) <- Seq(1, 2, 3) zip Seq(4, 5, 6)
} yield x + y


Out[14]:
res13: Seq[Int] = List(5, 7, 9)

ZIPWITHINDEX


In [15]:
for(x <- Seq(1, 2, 3).zipWithIndex) yield x


Out[15]:
res14: Seq[(Int, Int)] = List((1, 0), (2, 1), (3, 2))

Intermediate Result


In [16]:
for {
  x <- Seq(1, 2, 3)
  square = x * x
  y <- Seq(4, 5, 6)
} yield square * y


Out[16]:
res15: Seq[Int] = List(4, 5, 6, 16, 20, 24, 36, 45, 54)

OPTIONS


In [17]:
def readInt(str: String): Option[Int] = if (str matches "\\d+") Some(str.toInt) else None


Out[17]:
defined function readInt

In [18]:
readInt("!@#")


Out[18]:
res17: Option[Int] = None

In [19]:
readInt("123")


Out[19]:
res18: Option[Int] = Some(123)

In [20]:
readInt("a")


Out[20]:
res19: Option[Int] = None

In [21]:
readInt("1")


Out[21]:
res20: Option[Int] = Some(1)

In [22]:
// 값을 꺼내고 싶을 경우
readInt("abc").getOrElse(0)
// 값이 없다면 default 0 값


Out[22]:
res21: Int = 0

In [23]:
readInt("123") match {
  case Some(number) => number + 1
  case None => 0
}


Out[23]:
res22: Int = 124

options as sequences


In [ ]:
sealed abstract class Option[+A] extends Product with Serializable {
  def getOrElse(default: A): A
  def isEmpty: Boolean
  def isDefined: Boolean = !isEmpty
  def filter(func: A => Boolean): Option[A]
  def find(func: A => Boolean): Option[A]
  def map[B](func: A => B): Option[B]
  def flatMap(func: A => Option[B]): Option[B]
  def foreach(func: A => Unit): Unit
  def foldLeft[B](initial: B)(func: (B, A) => B): B
  def foldRight[B](initial: B)(func: (A, B) => B): B
}

In [24]:
def sum(optionA: Option[Int], optionB: Option[Int]): Option[Int] =
  optionA.flatMap(a => optionB.map(b=> a + b))

sum(readInt("1"), readInt("2"))
sum(readInt("1"), readInt("b"))
sum(readInt("a"), readInt("2"))


Out[24]:
defined function sum
res23_1: Option[Int] = Some(3)
res23_2: Option[Int] = None
res23_3: Option[Int] = None

In [25]:
def sum(optionA: Option[Int], optionB: Option[Int]): Option[Int] = for {
  a <- optionA
  b <- optionB
} yield a + b


Out[25]:
defined function sum

AVOIDING NULL POINTER EXCEPTIONS

  • option으로 감싸주면 nullpoint exception이 none으로 나와서 안전하게 쓸 수 있음

In [26]:
//proper way to wrap calls to java apis
val map = new java.util.HashMap[String, String]()
map.put("key1", "value1")
val maybeValue1 = Option(map.get("key1")) //Some("value1")
val maybeValue2 = Option(map.get("key2")) //None


Out[26]:
map: java.util.HashMap[String, String] = {key1=value1}
res25_1: String = null
maybeValue1: Option[String] = Some("value1")
maybeValue2: Option[String] = None

In [27]:
def readInt(str: String): Option[Int] = Option(str.toInt)


Out[27]:
defined function readInt

In [28]:
println(readInt("123"))


Some(123)

In [30]:
val ans0 = readInt("123") match { 
    case Some(number) => number + 1
    case None => 0
}


Out[30]:
ans0: Int = 124

In [31]:
val ans1 = readInt("123").fold(0)(_ + 1)
// 없으면 0 아니면 +1


Out[31]:
ans1: Int = 124

Exercise : A Simple Calculator


In [ ]:
def calculator(operand1: String, operator: String, operand2: String): String

In [ ]:
// 헬퍼 method를 2개 만듬
// string to int
// eval

In [32]:
def calculator(operand1: String, operator: String, operand2: String): String = {
  def readInt(str: String): Option[Int] = if (str matches "\\d+") Some(str.toInt) else None
  def eval(a: Int, op: String, b: Int): Option[Int] = op match {
    case "+" => Some(a + b)
    case "-" => Some(a - b)
    case "*" => Some(a * b)
    case "/" => if (b == 0) None else Some(a / b)
    case _ => None
  }
  val ansOp = for(a<-readInt(operand1); b<-readInt(operand2); ans<-eval(a, operator, b)) yield ans
  ansOp.fold(s"Error calculating $operand1 $operator $operand2")(ans => s"The answer is $ans!")
}

assert(calculator("1", "+", "1") == "The answer is 2!")
assert(calculator("1", "/", "0") == "Error calculating 1 / 0")

println("Ok!")


Ok!
Out[32]:
defined function calculator

Either

  • left, right
  • 값 하나하나 처리할 때 자주 쓰임

In [33]:
val right1 = Right(1)   : Right[Double, Int]
val right2 = Right(2)
val right3 = Right(3)
val left23 = Left(23.0) : Left[Double, Int]
val left42 = Left(42.0)


Out[33]:
right1: Right[Double, Int] = Right(1)
right2: Right[Nothing, Int] = Right(2)
right3: Right[Nothing, Int] = Right(3)
left23: Left[Double, Int] = Left(23.0)
left42: Left[Double, Nothing] = Left(42.0)
  • 아래 코드는 쥬피터에선 에러..

In [33]:
for {
  x <- right1
  y <- right2
  z <- right3
} yield x + y + z // Right(6)


cmd33.sc:2: value flatMap is not a member of Right[Double,Int]
  x <- right1
       ^cmd33.sc:3: value flatMap is not a member of scala.util.Right[Nothing,Int]
  y <- right2
       ^cmd33.sc:4: value map is not a member of scala.util.Right[Nothing,Int]
  z <- right3
       ^
Compilation Failed

In [33]:
for {
  x <- right1
  y <- right2
  z <- left23
} yield x + y + z // Left(23.0)


cmd33.sc:2: value flatMap is not a member of Right[Double,Int]
  x <- right1
       ^cmd33.sc:3: value flatMap is not a member of scala.util.Right[Nothing,Int]
  y <- right2
       ^cmd33.sc:4: value map is not a member of Left[Double,Int]
  z <- left23
       ^
Compilation Failed

In [33]:
for {
  x <- right1
  y <- left23
  z <- right2
} yield x + y + z // Left(23.0)


cmd33.sc:2: value flatMap is not a member of Right[Double,Int]
  x <- right1
       ^cmd33.sc:3: value flatMap is not a member of Left[Double,Int]
  y <- left23
       ^cmd33.sc:4: value map is not a member of scala.util.Right[Nothing,Int]
  z <- right2
       ^
Compilation Failed

Try

  • 명시적으로 성공과 실패가 존재

MAPS


In [34]:
val example = Map("a" -> 1, "b" -> 2, "c" -> 3)


Out[34]:
example: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3)

In [35]:
"a" -> 1


Out[35]:
res34: (String, Int) = ("a", 1)

In [36]:
example("a")


Out[36]:
res35: Int = 1

In [37]:
example.get("a")


Out[37]:
res36: Option[Int] = Some(1)

In [38]:
example("d")


java.util.NoSuchElementException: key not found: d
  scala.collection.MapLike$class.default(MapLike.scala:228)
  scala.collection.AbstractMap.default(Map.scala:59)
  scala.collection.MapLike$class.apply(MapLike.scala:141)
  scala.collection.AbstractMap.apply(Map.scala:59)
  $sess.cmd37Wrapper$Helper.<init>(cmd37.sc:1)
  $sess.cmd37Wrapper.<init>(cmd37.sc:391)
  $sess.cmd37$.<init>(cmd37.sc:218)
  $sess.cmd37$.<clinit>(cmd37.sc:-1)

In [39]:
example.get("d")


Out[39]:
res38: Option[Int] = None

In [40]:
example.getOrElse("d", -1)


Out[40]:
res39: Int = -1

In [41]:
example.contains("a")


Out[41]:
res40: Boolean = true

In [42]:
example.size


Out[42]:
res41: Int = 3

In [43]:
example.+("c" -> 10, "d" -> 11, "e" -> 12)


Out[43]:
res42: Map[String, Int] = Map("e" -> 12, "a" -> 1, "b" -> 2, "c" -> 10, "d" -> 11)

In [44]:
example.-("b", "c")


Out[44]:
res43: Map[String, Int] = Map("a" -> 1)

In [45]:
example + ("d" -> 4) - "c"


Out[45]:
res44: Map[String, Int] = Map("a" -> 1, "b" -> 2, "d" -> 4)

SORTEDMAPS


In [50]:
val map = Map("a"->1) + ("b"->2) + ("c"->3) + ("d"->4) + ("e"->5)


Out[50]:
map: Map[String, Int] = Map("e" -> 5, "a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)

In [51]:
map.toSeq


Out[51]:
res50: Seq[(String, Int)] = ArrayBuffer(("e", 5), ("a", 1), ("b", 2), ("c", 3), ("d", 4))

In [ ]:


In [48]:
// sort된 것이 보고싶다면
scala.collection.SortedMap("a"->1) + ("b"->2) + ("c"->3) + ("d"->4) + ("e"->5)


Out[48]:
res47: collection.SortedMap[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)

In [55]:
// scala 생략 가능
val map = collection.SortedMap("a"->1) + ("b"->2) + ("c"->3) + ("d"->4) + ("e"->5)


Out[55]:
map: collection.SortedMap[String, Int] = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)

In [56]:
map.toSeq


Out[56]:
res55: Seq[(String, Int)] = ArrayBuffer(("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5))

In [57]:
for {(k, v) <- map } yield s"($k->$v)"


Out[57]:
res56: Iterable[String] = List("(a->1)", "(b->2)", "(c->3)", "(d->4)", "(e->5)")

SETS

  • 순서가 보장되지 않음

In [60]:
val set = Set(1, 1, 2, 2, 3, 3)


Out[60]:
set: Set[Int] = Set(1, 2, 3)

In [64]:
// 정렬하고 싶다면
val set1 = scala.collection.SortedSet(1,2,3,4,5,6,7)


Out[64]:
set1: collection.SortedSet[Int] = TreeSet(1, 2, 3, 4, 5, 6, 7)

In [61]:
set.toSeq


Out[61]:
res60: Seq[Int] = ArrayBuffer(1, 2, 3)

In [65]:
set1.toSeq


Out[65]:
res64: Seq[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7)

In [63]:
for { x <- set } yield x * 2
// set을 연산해도 set


Out[63]:
res62: Set[Int] = Set(2, 4, 6)

In [66]:
for { x <- set1 } yield x * 2


Out[66]:
res65: collection.SortedSet[Int] = TreeSet(2, 4, 6, 8, 10, 12, 14)

RDD

  • API 문서를 같이 봤습니다. Spark때 다시 배울듯!

In [ ]: