Ninety-Nine Scala Problems (P35)

S-99を解く。

素因数分解

class IntWrapper(n:scala.Int) {
 def isPrime(n:Int): Boolean = (n != 1) &&
   (List.range(2,math.sqrt(n).toInt+1) forall (i => n % i != 0))
 def sieve(s: Stream[Int]): Stream[Int] =
   Stream.cons(s.head, sieve(s.tail filter (_ % s.head != 0)))

 val ps = sieve(Stream.from(2))
 def primeFactors: List[Int] = {
   def primeFactorsR(n: Int, ps: Stream[Int]): List[Int] =
     if (isPrime(n)) List(n)
     else if (n % ps.head == 0) ps.head :: primeFactorsR(n / ps.head, ps)
     else primeFactorsR(n, ps.tail)
   primeFactorsR(n, ps)
 }
}

implicit def int2IntWrapper(n:scala.Int) = new IntWrapper(n)

println("s35: " + 315.primeFactors)

エラトステネスの篩はここを参考にした。

Streamを使うと

def sieve(s: Stream[Int]): Stream[Int] =
   Stream.cons(s.head, sieve(s.tail filter (_ % s.head != 0)))

val ps = sieve(Stream.from(2))

とHaskellのように書ける

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


ScalaでSwing

GUIアプリを作るのにSwingを使ってみる

scala_swing

結構簡単そう。

import scala.swing._

object FirstSwingApp extends SimpleSwingApplication {
  def top = new MainFrame {
    title = "First Swing App"
    contents = new Button {
      text = "Click me"
    }
  }
}

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


Ninety-Nine Scala Problems (P33-P34)

S-99を解く。互いに素かどうか判定する問題と、それをつかってオイラーのφ関数を求める

class IntWrapper(n:scala.Int){
  def gcd(a:scala.Int, b:scala.Int): scala.Int =  if (b == 0) a else gcd(b, a % b)
  def isCoprimeTo(i:scala.Int): Boolean = gcd(n,i) == 1
  def totient: scala.Int = (1 to n) filter {(new IntWrapper(n)).isCoprimeTo(_)} length
}

implicit def int2IntWrapper(n:scala.Int) = new IntWrapper(n)

println("s33: " + 35.isCoprimeTo(64))
println("s34: " + 10.totient)

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


Ninety-Nine Scala Problems (P32)

S-99を解く。GCD実装するだけ、楽勝とおもったらへんなとこではまった。

対話環境では動く

scala> def gcd(a:Int, b:Int): Int =  if (b == 0) a else gcd(b, a % b)
gcd: (a: Int, b: Int)Int

scala> gcd(36,63)
res0: Int = 9

でも、スクリプトにして呼ぶとvalue % is not a member of Intっていうエラー

$ scala p32.scala 
/Users/kzfm/scala/p32.scala:2: error: value % is not a member of Int
def gcd(a:Int, b:Int): Int =  if (b == 0) a else gcd(b, a % b)

/Users/kzfm/scala/p32.scala:4: error: type mismatch;
 found   : scala.Int(36)
 required: Int
println(gcd(36, 63))

scala.Intって何?ってことで型の定義を変更したら動いた

def gcd(a:scala.Int, b:scala.Int): scala.Int =  if (b == 0) a else gcd(b, a % b)

println(gcd(36, 63))

よくわからん。

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


Ninety-Nine Scala Problems (P31)

S-99を解く。Int型にisPrimeっていう素数かどうかを判定するメソッドを組み込む問題。

implicit defをつかえばいい。

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


class IntWrapper(n:Int){
 def isPrime():Boolean = (n != 1) &&
(List.range(2,math.sqrt(n).toInt+1) forall (i => n % i != 0))
}

implicit def int2IntWrapper(n:Int) = new IntWrapper(n)

for (n <- 1 to 10)
 println(n + ": " + n.isPrime)

ところで、解答見たらstream使った例が載ってたんだけどこれ動かないんだけどナニが悪いの?

/Users/kzfm/scala/p31.scala:3: error: not found: value primes
    (start > 1) && (primes takeWhile { _ <= Math.sqrt(start) } forall { start % _ != 0 })
                    ^
/Users/kzfm/scala/p31.scala:7: error: value isPrime is not a member of Int
  val primes = Stream.cons(2, Stream.from(3, 2) filter { _.isPrime })

コード

class S99Int(val start: Int) {
  def isPrime: Boolean =
    (start > 1) && (primes takeWhile { _ <= Math.sqrt(start) } forall { start % _ != 0 })
}

object S99Int {
  val primes = Stream.cons(2, Stream.from(3, 2) filter { _.isPrime })
}

Ninety-Nine Scala Problems (P21 - P28)

S-99を解く。P25から先がちょいむず。

P26

組み合わせを求めるというオーソドックスな問題。n個からr個を選ぶ組み合わせは再帰的に考えると

  • (取り出したものを加える場合)は n-1個からr-1個を選ぶ
  • (取り出したものを加えない場合)はn-1個からr個を選ぶ

上記2つのパターンの和になるので、これで再帰させる。

def flatten(ls: List[Any]): List[Any] = ls flatMap {
 case ms: List[_] => flatten(ms)
 case e => List(e)
}

def combinations(n:Int, ls:List[Any]): List[List[Any]] =
 if (n==0) List(Nil)
 else if (ls == Nil) List(Nil)
 else ((combinations(n-1,ls.tail) map ((e:List[Any]) => ls.head :: flatten(e))) ::: combinations(n,ls.tail))

println(combinations(3, List('a, 'b, 'c, 'd)) filter (l => l.length == 3))
println(combinations(3, List('a, 'b, 'c, 'd)))

結局r個以下の組み合わせを出力する関数になってしまった。しょうがないのでfilterかましてるけど。 あと、型がうまく決められなかったので、Anyとか使っちゃったけどあんまり良くない気がする。

ProductName Scalaスケーラブルプログラミング第2版
Martin Odersky
インプレスジャパン / 4830円 ( 2011-09-27 )


//21
def insertAt[A](e:A, n:Int, ls:List[A]): List[A] = {
  val v = ls.splitAt(n)
  v._1 ::: e :: v._2
}

println("s21: "+ insertAt('new, 1, List('a, 'b, 'c, 'd)))

//22
def range(s:Int, e:Int): List[Int] = List.range(s,e+1)

println("s22: " + range(4, 9))

//23 Randomの使い方を知らなかった
def removeAt[A](n:Int, ls:List[A]): (List[A],A) = {
  val v = ls.splitAt(n)
  (v._1 ::: v._2.tail, v._2.head)
}

def randomSelect[A](n: Int, ls: List[A]): List[A] =
  if (n <= 0) Nil
  else {
    val (rest, e) = removeAt((new util.Random).nextInt(ls.length), ls)
    e :: randomSelect(n - 1, rest)
  }

println("s23: " + randomSelect(3, List('a, 'b, 'c, 'd, 'f, 'g, 'h)))

//24
def lotto(n: Int, r: Int): List[Int] = 
  if (n <=0) Nil
  else randomSelect(n, List.range(1,r+1))

println("s24: " + lotto(6, 49))

//25
def randomPermute[A](ls:List[A]): List[A] = lotto(ls.length,ls.length) map(e => ls(e-1))

println("s25: " + randomPermute(List('a, 'b, 'c, 'd, 'e, 'f)))

//26
//def combinations[A](n:Int, ls:List[A]): List[List[Any]] = 
//  if (n == 0) Nil
//  else if (ls == Nil) Nil
//  else ( ls.head :: combinations(n-1,ls.tail) ) :: combinations(n,ls.tail)

def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = 
  ls match {
    case Nil => Nil
    case sublist@(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
  }

def combinations[A](n: Int, ls: List[A]): List[List[A]] =
  if (n == 0) List(Nil)
  else flatMapSublists(ls) { sl =>
    combinations(n - 1, sl.tail) map {sl.head :: _}
               }

println("s26: " + combinations(3, List('a, 'b, 'c, 'd, 'e, 'f)))

//27
//println("s27: " + )
//28
//println("s28: " + )

Ninety-Nine Scala Problems (P11 - P20)

S-99を解く。List.makeを使ったらdeprecation warningsがでたので、fillにしてみたんだけどこれでいいのだろうか?

scala> List.make(5,3)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
res5: List[Int] = List(3, 3, 3, 3, 3)

pythonのenumerateはscalaではzipWithIndexでこれを使えばp16は

ls.zipWithIndex filter { v => (v._2 + 1) % n != 0 } map { _._1 }

splitAtメソッド使えばリストを2つに分割(P17)できるが、僕はtakeとdrop使ってた。

//11
def pack[A](ls:List[A]): List[List[A]] = ls match {
  case Nil => Nil
  case head::tail => ls.takeWhile(_ == head) :: pack(tail.dropWhile(_ == head))
}

def encodeModified[A](ls: List[A]): List[Any] = pack(ls) map {
  e => if (e.length == 1) e.head else (e.length, e.head)
}

println("s11: " + encodeModified(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))

//12
//scala> List.make(5,3)
//warning: there were 1 deprecation warnings; re-run with -deprecation for details
//res5: List[Int] = List(3, 3, 3, 3, 3)

def decode[A](ls:List[(Int, A)]): List[A] = ls flatMap {e => List.fill(e._1)(e._2)}

println("s12: " + decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))))

//13
def encodeDirect[A](ls:List[A]): List[(Int, A)] = ls match {
  case Nil => Nil
  case head::tail => (ls.takeWhile(_ == head).length, head) :: encodeDirect(tail.dropWhile(_ == head))
}

println("s13: " + encodeDirect(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))

//14
def duplicate[A](ls:List[A]): List[A] = ls match {
  case Nil => Nil
  case h::t => h::h::duplicate(t)
}

println("s14: " + duplicate(List('a, 'b, 'c, 'c, 'd)))

//15
def duplicateN[A](n:Int, ls:List[A]): List[A] = ls flatMap {e => List.fill(n)(e) }

println("s15: " + duplicateN(3, List('a, 'b, 'c, 'c, 'd)))

//16
//  // Functional.
//  def dropFunctional[A](n: Int, ls: List[A]): List[A] = 
//    ls.zipWithIndex filter { v => (v._2 + 1) % n != 0 } map { _._1 }
//}

def drop[A](n:Int, ls:List[A]): List[A] = {
  def drop2[A](n:Int, ls:List[A]): List[A] = ls match {
    case Nil => Nil
    case _ => ls.take(n-1) ::: drop2(n, ls.drop(n))
  }
  drop2(n,ls)
}

println("s16: " + drop(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)))

//17
// Builtin.
//  def splitBuiltin[A](n: Int, ls: List[A]): (List[A], List[A]) = ls.splitAt(n)

def split[A](n:Int, ls:List[A]): (List[A],List[A]) = (ls.take(n), ls.drop(n))

println("s17: " + split(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)))

//18
def slice[A](s:Int, e:Int, ls:List[A]): List[A] = ls.take(e).drop(s)

println("s18: " + slice(3, 7, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)))

//19
def rotate[A](n:Int, ls:List[A]): List[A] = {
  if (n >= 0)  ls.drop(n) ::: ls.take(n)
  else ls.drop(ls.length + n) ::: ls.take(ls.length + n)
}

println("s19: " + rotate(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)))
println("s19: " + rotate(-2, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k)))

//20
def removeAt[A](n:Int, ls:List[A]): (List[A],A) = {
  val v = ls.splitAt(n)
  (v._1 ::: v._2.tail, v._2.head)
}

println("s20: " + removeAt(1, List('a, 'b, 'c, 'd)))

Ninety-Nine Scala Problems (P01 - P10)

S-99を解く。Scalaは基本は関数型で考えて、どうしようもないときにはOOPに逃げられるのがいいですね。

//1
def last[A](ls:List[A]): A = ls.last

println("s1: " + last(List(1, 1, 2, 3, 5, 8)))

//2
def penultimate[A](ls:List[A]): A = ls.init.last

println("s2: " + penultimate(List(1, 1, 2, 3, 5, 8)))

//3
def nth[A](n:Int, ls:List[A]): A = if (n == 0) ls.head else nth(n-1,ls.tail)

println("s3: " + nth(2, List(1, 1, 2, 3, 5, 8)))

//4
def length[A](ls:List[A]): Int = ls.length

println("s4: "+ length(List(1, 1, 2, 3, 5, 8)))

//5
def reverse[A](ls:List[A]): List[A] = {
  def reverse2[A](ls:List[A],ls2:List[A]): List[A] = ls match {
      case Nil => ls2 
      case (head::tail) => reverse2(tail,head::ls2)
    }
  reverse2(ls,Nil)
}
println("s5: " + reverse(List(1, 1, 2, 3, 5, 8)))

//6
def isPalindrome[A](ls:List[A]): Boolean = ls == reverse(ls)

println("s6: " +  isPalindrome(List(1, 2, 3, 2, 1)))

//7
def flatten(ls: List[Any]): List[Any] = ls flatMap {
  case ms:List[_] => flatten(ms)
  case e => List(e)
}

println("s7: " + flatten(List(List(1, 1), 2, List(3, List(5, 8)))))

//8
def compress[A](ls:List[A]): List[A] = ls match {
  case Nil    => ls
  case head::tail => head::compress(tail.dropWhile(_ == head))
}

println("s8: " + compress(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))

//9
def pack[A](ls:List[A]): List[List[A]] = ls match {
  case Nil => Nil
  case head::tail => ls.takeWhile(_ == head) :: pack(tail.dropWhile(_ == head))
}

println("s9: " + pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))

//10
def encode[A](ls: List[A]): List[(Int, A)] = pack(ls) map {e => (e.length, e.head)}

println("s10: " + encode(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))

部分関数でFizzBuzz

部分関数って離散数学とかの集合論をやると理解しやすいよなぁと。

ProductName 離散数学への招待〈上〉
J. マトウシェク
シュプリンガー・フェアラーク東京 / 2835円 ( 2002-12 )


ScalaのPartialFunctionを使って。

object FizzBuzz {
  val PFizz:PartialFunction[Int,String] = { case n if n%3==0 => "Fizz" }
  val PBuzz:PartialFunction[Int,String] = { case n if n%5==0 => "Buzz" }
  val PFizzBuzz:PartialFunction[Int,String] = { case n if n%15==0 => "FizzBuzz" }
  val PInt:PartialFunction[Int,String] = {case n => n.toString}

  val FizzBuzz = PFizzBuzz orElse PBuzz orElse PFizz orElse PInt

  def main(arg:Array[String]) = {
    println((1 to 30).toList.map(FizzBuzz(_)))
  }
}

Scalaはコップ本よりもこっちのほうが好みかな

ProductName Scalaプログラミング入門
デイビッド・ポラック
日経BP社 / 3360円 ( 2010-03-18 )


シンプソン積分をScalaで

Pythonで書いたシンプソン積分をScalaでも書いてみたのだけどfor yieldで総和を求めるやり方が分からなかったので(RandomAccessSeq.Projectionとかいうのが出た)結局var変数で。

def simpson(f: Double => Double, a: Double, b: Double, n: Int): Double = {
  val h = (b - a)/n
  var sum = 0.0
  for (i <- 0 to n-1) {
    sum = sum + f(a+i*h) + 4.0 * f(a+i*h+h/2) + f(a+i*h+h)
  }
  sum * h / 6
}

def func(x: Double): Double = {
  1.0 / (1 + Math.pow(x,2))
}

実行

scala> simpson(func, 0, 1, 1000)
res24: Double = 0.7853981633974496

Int,Double,Floatとかの型の使い方もいまいちわかってないな。