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のコレクションとかについて

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) )}