x13. Scala(2/2)
2016年度目標: 昨年同様
2015年度目標: あきすとぜねこ 占いのプログラムを関数スタイルで作成。
Scalaの文字列処理
http://gendosu.jp/archives/1344
ストリーム練習
object Main {
def main(args: Array[String]) = {
def Ones:Stream[Int] = 1 #:: Ones
println(Ones.take(8).toList)
def PlusOnes:Stream[Int] = 1 #:: PlusOnes.map( _ + 1)
println(PlusOnes.take(8).toList)
}}
あきすとぜねこ ヒント
scala> val AK:Stream[Char] = 'あ' #::'き' #::'す' #::'と' #::'ぜ' #::'ね' #:: 'こ' #:: AK
AK: Stream[Char] = Stream(あ, ?)
scala> AK(3)
res18: Char = と
scala> AK.take(3)
res19: scala.collection.immutable.Stream[Char] = Stream(あ, ?)
scala> AK.take(3).toList
res20: List[Char] = List(あ, き, す)
scala> "KOBASHI".filter("AIUEON" contains _)
res21: String = OAI
scala> "KOBASHI".filter("SXYZ" contains _)
res26: String = S
制作例) 一部省略しているので、完成させてみよう。
※Test.scala に以下を追記
※プログラムを実行する際には、 実行の構成 から メイン・クラス を Main に変更する。
object Main {
def main(args: Array[String]) = {
// あきすとぜねこ 判定用の遅延リストで判定用数字が7を超えた場合に対応
// ※普通は、遅延リストを使わずに、判定用数字を7で割った余りに変換して、Listを使う
lazy val AK: Stream[Char] = 'あ' #:: 'き' #:: 'す' #:: 'と' #:: 'ぜ' #:: 'ね' #:: 'こ' #:: AK
def kekka(n: Int) = ('う' #:: AK)(n) match {
case 'う' => "運命の人"
case 'あ' => "愛してる"
case _ => "内緒"
}
// ひらがなの名前を、AIUEON に変換 長音記号 - やカタカナにも対応させてみよう
def RtoAIU(str: String) = str.map(_ match {
case c if "あかがさざただなはばぱまやらわ" contains c => 'A'
case c if "いきぎしじちぢにひびぴみり" contains c => 'I'
case c if "うくぐすずつづっぬふぶぷむゆゅる" contains c => 'U'
case c if "えけげせぜてでねへべぺめれ" contains c => 'E'
case c if "おこごそぞとどのほぼぽもよろを" contains c => 'O'
case 'ん' => 'N'
})
def HtoNums(str: String) = str.map(_ match {
case 'A' => 1
case 'I' => 2
case 'U' => 3
case 'E' => 4
case 'O' => 5
case 'N' => 1
})
def ZNK(str1: String, str2: String) = {
val R1 = RtoAIU(str1)
val R2 = RtoAIU(str2)
val D1 = R1.filter(c => !(R2 contains c))
val D2 = R2.filter(c => !(R1 contains c))
val N1 = D1.sum
val N2 = D2.sum
(kekka(N1), kekka(N2))
}
def printZNK(str1: String, str2: String) {
val s = ZNK(str1, str2)
println(s"${str1} → ${str2} 結果は ${s._1}")
println(s"${str2} → ${str1} 結果は ${s._2}")
}
// 本来、姓の後に名を記入して占う
val name1 = "こばし"
val name2 = "はせがわ"
val name3 = "はっとり"
printZNK(name1,name2)
printZNK(name1,name3)
}
}
実行結果:
こばし → はせがわ 結果は 内緒
はせがわ → こばし 結果は 内緒
こばし → はっとり 結果は 運命の人
はっとり → こばし 結果は 愛してる
以下 2014年度の内容:
(先週の資料 後半部分の続き)
Scala のデータ型である リスト を関数型スタイルで処理し、 サウンド再生用データを作成する。
音響合成プログラミングを行う。
応用 「エンジニアでも恋がしたい!」 http://paiza.jp/poh/enkoi の問題に Scala で挑戦
解答編:
問2
object Main extends App{
override def main(args:Array[String]) = {
val sc = new java.util.Scanner(System.in)
val n = sc.nextInt
var sum = 0
for(i <- 1 to n) {
val a,b,c = sc.nextInt
if(a>b) {
sum += (a-b)*c
}
}
println(sum)
}
}
問3
配列版
object Main extends App{
override def main(args:Array[String]) = {
val sc = new java.util.Scanner(System.in)
val t = sc.nextInt
val n = sc.nextInt
val ms = new Array[Int](t)
for(i <- 0 to t - 1) {
ms(i) = sc.nextInt
}
var sum = ms.sum
var max = sum
for(i <- 0 to n - t - 1) {
val a = ms(i % t)
val b = sc.nextInt
ms(i % t) = b
sum = sum - a + b
if(sum > max) {
max = sum
}
}
println(max)
}
}
リスト版(単純版)
object Main extends App{
override def main(args:Array[String]) = {
val sc = new java.util.Scanner(System.in)
val t = sc.nextInt
val n = sc.nextInt
var max = 0
var ms:List[Int] = Nil
for(i <- 1 to t) {
ms = ms :+ sc.nextInt
}
max = ms.sum
for(i <- 1 to n-t) {
ms = ms.tail :+ sc.nextInt
val sum = ms.sum
if(sum > max) {
max = sum
}
}
println(max)
}
}
リスト版(高速化版)
object Main extends App{
override def main(args:Array[String]) = {
val sc = new java.util.Scanner(System.in)
val t = sc.nextInt
val n = sc.nextInt
var ms:List[Int] = Nil
for(i <- 1 to t) {
ms = ms :+ sc.nextInt
}
var sum = ms.sum
var max = sum
for(i <- 1 to n-t) {
val b = sc.nextInt
val a = ms.head
ms = ms.tail :+ b
sum = sum - a + b
if(sum > max) {
max = sum
}
}
println(max)
}
}
Scala のリスト処理の参考サイト:
Scalaの配列について:
Scalaプログラミングで知っておきたい基本構文まとめ (1/2)
Scalaのストリームについて
https://sites.google.com/site/scalajp/home/documentation/scala-by-example/chapter12
http://scalajp.github.io/scala-collections-doc-ja/collections_14.html
Java8 のストリームAPIについて Stream APIの始め方
例)
object Main {
def main(args:Array[String]) = {
println( fix(1).take(10).toList )
println( up(1).take(10).toList )
println( up(10).take(20).filter(_%2==0).toList )
println( up(10).filter(_%2==0).take(20).toList )
}
def fix(x:Int):Stream[Int] = x #:: fix(x)
def up(x:Int):Stream[Int] = x #:: up(x+1)
}
出力結果
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1) List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) List(10, 12, 14, 16, 18, 20, 22, 24, 26, 28) List(10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48)
演習課題:
・環境構築
レポートフォルダ オブジェクト指向(小橋) にある scala フォルダを D: ドライブにコピー。 もしも時間がかかり過ぎるようなら、コピーしない方式も検討。
環境変数に java のパスを設定
JAVA_HOME = D:\java\8
windowsのコマンドプロンプトを開く
scala REPL の起動
Scalaのインストールされたフォルダに移動
> d:
> cd \scala\bin
> scala
(参考)
Javaでピコピコシンセを作ってみよう!(1) - ピコピコ音の正体を暴く http://www.hakkaku.net/articles/20090423-422
Programming music http://vigtig.it/blog/blog/2011/04/12/programming-music/
ビープ音の合成
import javax.sound.sampled._
// オーディオ形式を指定
val SAMPLE_RATE = 44100; // 44.1KHz
val audio_format = new AudioFormat(SAMPLE_RATE, 8, 1, true, true)
val line = AudioSystem.getSourceDataLine(audio_format)
line.open()
line.start()
// バイト列に適当な矩形波を作成
val frequency = 440
val b = new Array[Byte](SAMPLE_RATE)
for (i <- 0 to b.size) {
val r = i / (SAMPLE_RATE / frequency)
if( r % 2 == 0) { b(i) = 100 } else { b(i) = -100 }
}
// 再生(バイト列を line に書き込む)
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
波形を修正する。
ループ部分の式を 調整して 音を変えてみる。
試したたコードを、 学籍番号Scala2.txt のテキストファイルにコピペして提出。
// Test
val i = 123
println(i * 2)
import javax.sound.sampled._
// Test 1
// オーディオ形式を指定
val SAMPLE_RATE = 44100; // 44.1KHz
val audio_format = new AudioFormat(SAMPLE_RATE, 8, 1, true, true)
val line = AudioSystem.getSourceDataLine(audio_format)
line.open()
line.start()
// バイト列に適当な矩形波を作成
val frequency = 440
val b = new Array[Byte](SAMPLE_RATE)
for (i <- 0 to b.size) {
val r = i / (SAMPLE_RATE / frequency)
if( r % 2 == 0) { b(i) = 100 } else { b(i) = -100 }
}
// 再生(バイト列を line に書き込む)
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
// Test 2 再生時間を10倍 長くする
val SAMPLE_RATE = 44100; // 44.1KHz
val audio_format = new AudioFormat(SAMPLE_RATE, 8, 1, true, true)
val line = AudioSystem.getSourceDataLine(audio_format)
line.open()
line.start()
val frequency = 440
val b = new Array[Byte](SAMPLE_RATE * 10)
for (i <- 0 to b.size) {
val r = i / (SAMPLE_RATE / frequency)
if( r % 2 == 0) { b(i) = 100 } else { b(i) = -100 }
}
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
// Test 3 再生時間を半分にして 音の周波数を 2倍(1オクターブ上)にする
val frequency = 880
val b = new Array[Byte](SAMPLE_RATE/2)
for (i <- 0 to b.size) {
val r = i / (SAMPLE_RATE / frequency)
if( r % 2 == 0) { b(i) = 100 } else { b(i) = -100 }
}
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
// Test 3 2オクターブ上にする
val frequency = 880*2
val b = new Array[Byte](SAMPLE_RATE/2)
for (i <- 0 to b.size) {
val r = i / (SAMPLE_RATE / frequency)
if( r % 2 == 0) { b(i) = 100 } else { b(i) = -100 }
}
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
// r = i / 500
// Test 4 ホワイトノイズ
import scala.util.Random
List.fill(10)(Random.nextInt(10))
val b = List.fill(SAMPLE_RATE)((Random.nextInt(200)-100).toByte).toArray
line.write(b, 0, b.length);
line.drain(); // 終了まで待機
音源データの波形を表示する。
// b1 から100個データを取り出し、 各データの値 e を e個の "." で1行に表示する
b1.take(100) foreach {e => println( "." * e )}
// b1 から300個データを取り出し、 各データの値 e を e/2個の "." で1行に表示する
// 高さが半分になる
b1.take(300) foreach {e => println( "." * e/2 )}
// データの値 e が -128..0 の場合、-128 は0個 -127 は1個のように、"."を表示する
//
b1.take(300) foreach {e => println( "." * (e+128) )}