S-99: Ninety-Nine Scala Problems(P11-P20)を解いてみた
S-99: Ninety-Nine Scala Problems(P01-P10)を解いてみたの続き。今回は、表題の通り、P11-P20までを解いてみた。とりあえず最初の回答を作るまでに大体50分くらい。その後、dropとrotateについて題意を勘違いしていたのに気づいてコードを修正。
以下、回答のコード。
object P11toP20 { import P01toP10._ def flatMap[A, B](list: List[A])(f: A => List[B]): List[B] = { foldLeft(list, List[B]()){(b, a) => append(b, f(a))} } def copyN[T](t: T, n: Int): List[T] = n match { case 0 => List() case n if n > 0 => t::copyN(t, n - 1) case _ => error("") } def encodeModified(list: List[Any]): List[Any] = { map(pack(list)){x => length(x) match { case 1 => x.head case n => (n, x.head) } } } def decode[T](encoded: List[(Int, T)]): List[T] = { flatMap(encoded){ case (n, e) => copyN(e, n) } } def encodeDirect[T](list: List[T]): List[(Int, T)] = { def encodeDirect1(pre: T, n: Int, rest: List[T]): List[(Int, T)] = { rest match { case x::xs if pre == x => encodeDirect1(pre, n + 1, xs) case x::xs => (n, pre)::encodeDirect1(x, 1, xs) case _ => List((n, pre)) } } list match { case x::xs => encodeDirect1(x, 1, xs) case _ => List() } } def duplicate[T](list: List[T]): List[T] = { flatMap(list){ case x => List(x, x) } } def duplicateN[T](n: Int, list: List[T]): List[T] = { flatMap(list){ case x => copyN(x, n) } } def drop[T](nth: Int, list: List[T]): List[T] = { def drop1[T](mth: Int, list: List[T]): List[T] = list match { case x::xs if mth == 1 => drop1(nth, xs) case x::xs if mth > 1 => x::drop1(mth - 1, xs) case _ => List[T]() } if(nth > 0) drop1(nth, list) else error("") } def split[T](n: Int, list: List[T]): (List[T], List[T]) = list match { case xs if n == 0 => (List[T](), xs) case x::xs if n > 0 => split(n - 1, xs) match { case (a, b) => (x::a, b) } case _ => error("") } def slice[T](i: Int, k: Int, list: List[T]): List[T] = { def slice1[T](i: Int, k: Int, list: List[T]): List[T] = list match { case x::xs if i > 0 => slice(i - 1, k - 1, xs) case x::xs if k > 0 => x::slice(0, k - 1, xs) case _ if i == 0 => List[T]() case _ => error("") } if(0 <= i && i <= k) slice1(i, k, list) else error("") } /* abs(n) <= length(list)を仮定してしまっていたので、間違い。 def rotate[T](n: Int, list: List[T]): List[T] = { def rotate_+(n: Int, list1: List[T], list2: List[T]): List[T] = list1 match { case x::xs if n > 0 => rotate_+(n - 1, xs, x::list2) case _ if n == 0 => append(list1, reverse(list2)) case _ => error("") } def rotate_-(n: Int, list1: List[T], list2: List[T]): List[T] = list1 match { case x::xs if n > 0 => rotate_-(n - 1, xs, x::list2) case _ if n == 0 => append(list2, reverse(list1)) case _ => error("") } if(n > 0) rotate_+(n, list, List[T]()) else if(n < 0) rotate_-(-n, reverse(list), List[T]()) else List[T]() } */ def rotate[T](n: Int, list: List[T]): List[T] = { def rotate_+-(n: Int, visit: List[T], rest: List[T]): List[T] = n match { case n if n > 0 => rest match { case Nil => rotate_+-(n, Nil, reverse(visit)) case x::xs => rotate_+-(n - 1, x::visit, xs) } case n if n < 0 => visit match { case Nil => rotate_+-(n, reverse(rest), Nil) case x::xs => rotate_+-(n + 1, xs, x::rest) } case 0 => append(rest, reverse(visit)) } list match { case Nil => error("") case _ => rotate_+-(n, Nil, list) } } def removeAt[T](nth: Int, list: List[T]): (List[T], T) = list match { case x::xs if nth == 0 => (xs, x) case x::xs if nth > 0 => removeAt(nth - 1, xs) match { case (ys, y) => (x::ys, y) } case _ => error("") } }
実行例。
scala> import P11toP20._ import P11toP20._ scala> encodeModified(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)) res0: List[Any] = List((4,'a), 'b, (2,'c), (2,'a), 'd, (4,'e)) scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))) res1: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e) scala> encodeDirect(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)) res2: List[(Int, Symbol)] = List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e)) scala> duplicate(List('a, 'b, 'c, 'c, 'd)) res3: List[Symbol] = List('a, 'a, 'b, 'b, 'c, 'c, 'c, 'c, 'd, 'd) scala> duplicateN(3, List('a, 'b, 'c, 'c, 'd)) res4: List[Symbol] = List('a, 'a, 'a, 'b, 'b, 'b, 'c, 'c, 'c, 'c, 'c, 'c, 'd, 'd, 'd) scala> drop(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) res5: List[Symbol] = List('a, 'b, 'd, 'e, 'g, 'h, 'j, 'k) scala> split(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) res6: (List[Symbol], List[Symbol]) = (List('a, 'b, 'c),List('d, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) scala> slice(3, 7, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) res7: List[Symbol] = List('d, 'e, 'f, 'g) scala> rotate(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) res8: List[Symbol] = List('d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'a, 'b, 'c) scala> rotate(-2, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)) res9: List[Symbol] = List('j, 'k, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i) scala> removeAt(1, List('a, 'b, 'c, 'd)) res10: (List[Symbol], Symbol) = (List('a, 'c, 'd),'b)
追記:
nの絶対値がlength(list)より小さいことを仮定してしまっていたため、rotateの定義を修正。これで、以下のように動作するようになった。
scala> rotate(5, List('a, 'b, 'c)) res6: List[Symbol] = List('c, 'a, 'b)