Python Introduction part2
基本的なコレクションの一つであるStringについて。
PythonのStringはScalaのものと比べるとCharの連続したものであるということがより伝わってくる。気がする…PythonのListとStringの大きな違いとしてmutablityがある。Listはmutableな一方でStringはimmutable。len()など基本的なメソッドはListとかぶっているけどcenter(),rjust(),ljust()メソッドとかがあまりなじみないな。center()はintを受け取り、(その数値ーStringの文字列)/2の分だけ両側に空白を作る。rjust,ljustはそれぞれ左、右どちらかにその空白を偏らせる。ただし、上の3つのメソッドは引数の数値が文字列の長さ以下の時、何も起こらない
name="david"
=>"david"
name[0]
=>"d"
name.upper()
=>"DAVID"
name.center(10)
=>" david "
name.rjust(10)
=>" david"
name.ljust(10)
=>"david "
name.find("a")
=>1 //indexを教えてくれる
name.split("a")
=>["d","vid"]
splitは文字列を受け取りその文字列をStringから取り除き残ったStringを前後に分断してList化するメソッド。もし仮に受け取る文字列が調べるStringと一致していなかったら何も行われない(例えば引数が"av"なら機能するが"ai"なら何もしない)。ちなみにもし受け取る引数が調べるStringの末尾の部分ならリストの中の後ろの要素は空のStringが渡される。
続いてTupleについて。これはListとかなり似ているのだけど、こちらはimmutable.
tp=(1,2,True,5.5)
len(tp)
=>4
tp[0:3:1] //index3は含まない
=>1,2,True
次はSet。setは順序のないTuple.ただしimmutableなオブジェクトを格納するコレクションなだけであってコレクション自体はmutable。setは{ }で囲う。順序がないからインデックスをどうこうはできないけどその代わり記号を使ったわかりやすいメソッドがある。イメージ的にはsetは集合みたいなかんじだなあ。基本的に重複しないのかな… A | B はAとBの和集合的な(重複しない)。A & B はAとBに共通する要素の集合。A-BはAからBに含まれる要素を差し引いた要素の集合。最後のA<=BはBがAを包括しているかどうかを確認するためのメソッドといったところか。
st={5.5,True,2}
st2=>{7,False,5.5,2}
st | st2
=>{5.5,True,2,False,7}
st & st2
=>{5.5,2}
st2-st
=>{7,False}
st <= st2
=>False
たぶんだけど記号のメソッドは実際にはそれぞれに対応しているメソッドに変換されていると思われる。例えば A | B は A.union(B) 、A & B は A.intersection(B)、A - B は A.difference(B) 、A <= B は A.insubset(B) へと変換されている。たぶん。 add(),remove(),pop()等のメソッドも使用出来、clear()メソッドも実装されている。これはその名の通り。
最後のコレクションはdictionary。これはScalaでいうMapコレクション。Mapだからもちろん順序が存在しない。純粋にkey-valueの関係だけ。基本的にScalaのMapと酷似してるから問題ないとおもう。要素の削除と追加は以下の感じ。
capitals={"Hokkaido":"Sapporo","Tokyo":"Tokyo"}
del capitals["Hokkaido"]
=>{"Tokyo":"Tokyo"}
capitals["Hokkaido"]="Sapporo"
=>{"Hokkaido":"Sapporo","Tokyo":"Tokyo"}
要素の参照は2通りあり、dic[key]の場合もし対応するkeyが存在してない場合エラーとなるがdic.get(key)を使えば何も返されずエラーが起きない。dic.get(key, alternative objects)、このようにさらに引数を一つ追加すると対応するkeyが発見されなかった時に返す値をしてして受け取ることが出来る。
capitals["Hokkaido"]
=>"Sapporo"
capitals.get("Hokkaido")
=>"Sapporo"
"Hokkaido" in capitals // keyのみ調べる
=>True
for k in capitals:
print("key: "+k+", value: "+capitals[k])
=>key: Hokkaido, value: Sapporo
=>key: Tokyo, value: Tokyo
capitals.keys()
=>["Hokkaido","Tokyo"] //keyのListが返される。
capitals.values()
=>["Sapporo","Tokyo"]
capitals.items()
=>[("Hokkaido","Sapporp"),("Tokyo","Tokyo")] //List[Tuple(T,T)]の形で返される
Python Introduction part1
「Python来週までに使えるようにねー」
ってアルゴリズムの授業で言われたんで急ごしらえで基礎的なところの細かな違いをちゃちゃっと確認する。初っ端から飛ばしてるわこの教授…教授に言われて参考にしたサイトはこちら。
Introduction — Problem Solving with Algorithms and Data Structures
まずClass Data Typeから。int, float, bool(Booleanのこと)など、小文字っすね。ScalaじゃBooleanみたいに大文字だったな。operationに関しては&&がand、||がor、!=がnotとなっており記号はあんまり使いたがらないのかな?
次にコレクションに関して。Lists,Strings,Tuplesなどがある。今回はListから。
list=[1,3,True,5.5]
newlist=[list]*2
list[2]=False
print(newlist)
まず特筆すべきなのは異なる型を格納可能ということ。
次に、Scalaと違ってmutableであること(もちろんScalaでもmutableなコレクションは可能だが)。故に特定の要素を上書きすることができる。ここでは要素の3つ目をTrueからFalseに書き換えているが、もし2行目を
newlist=list*2
このようにすると3行の更新はnewlistに反映されずnewlistにFalseが出てくることはない。加えて、[ ]をつけた場合newlistは[ [list], [list] ]となるがつけないと[ ]となりlist2つ分の要素が区切られることなく連続したリストが作成される
特定のオブジェクトがリストに含まれているのかを確認と長さを求める
1 in list
=>True
len(list)
=>4
部分要素の取得
list[1:3]
=>[3,False,5.5]
list[:1]
=>[1,3]
リストの初期化
list=[0]*len(list)
=>[0,0,0,0]
末尾に要素を追加
list.append(3)
=>[1,3,False,5.5,3]
要素を特定の位置に追加
list.insert(2,True)
=>[1,3,True,False,5.5,3]
要素の削除
del list[3]
=>4番目の要素を削除
list.remove(3)
=>3をリストから一つ削除(インデックスではない)
末尾要素を取得しリストから削除
list.pop()
=>3
list
=>[1,3,False,5.5]
list.append(3)
=>[1,3,False,5.5,3]
list.pop(1)
//特定の要素を取得し削除することも可能 (取得しないで削除は"del list[object]". 逆に取得して削除しないのはindex( )
=>3
list
=>[1,False,5.5,3]
ソート
list.sort()
list
=>[False,1,3,5.5]
リバース
list.reverse
単純な範囲を求める
range(1,10)
=>[1,2,3,4,5,6,7,8,9]
range(15,10,-1)
=>[15,14,13,12,11]
入力処理… Iterator continually
scala.ioをディスってる記事にちょくちょく載ってる(こっちの方がいいよ的な意味で)Iterator continuallyが良いなと思ったんでめもる。
val lines=Iterator.continually(readLine).takeWhile(_ != "finish")
lines.foreach(println)
これで"finish"が入力されるまで入力を続け、そのIteratorからforeach&printlnを使い出力できる。Iterator.continuallyの引数は繰り返される処理(ここではreadLine)を入れる。takeWhileは引数の中の条件がfalseになるまでを取得っつーことだからここでは"finish"が出るまで。あとはforeachで回せば出来上がり。
ちなみにIteratorは一度使ったらなくなっちまうからリストに入れるなり保存したりも…
val lines=Iterator.continually(readLIne).takeWhile(_ != "finish").toList
なるほどね〜
誰だよこんなの思いついたやつ
scalaのStreamを使った無限フィボナッチ数列の作り方っ★
※StreamとはListを遅延評価にしたようなやつ。遅延評価なので実際にその値が必要になるまで評価されず、無限に要素を持つことが可能。
なんか普通に綺麗で、思いついたやつcrazyだと思う。
def fib(a:Int,b:Int):Stream[Int]=a#::fib(b,a+b)
これだけで無限フィボナッチ数列の完成。
a,bには最初の2つの数字をいれてあげる。#::はListの::と同じで、Streamを作成してくれる。例えば fib(1,10) と打ち込むと無限にフィボるので注意笑。fib(1,10).take(10) これで先頭が1,10から始まるフィボナッチ数列の先頭から10個目までを取得できる。ただ、この段階ではまだ評価されない。
Stream(1,?)
こんな感じで先頭の要素しか評価されとらん。
fib(1,10).take(10).foreach(println)
とかして初めて評価される
1
10
11
21
32
53
85
138
223
361
こんな感じですごい不思議なくらいすっきりしてる。
fib(1,10).take(5).filter(x=>x%2==0)
ぱないっす。
Iteratee, Websocket周りのメモ書き
server側のwebsocketコード
def ws =WebSocket.using[String]{ request =>
val in=Iteratee.foreach[String]{str => str match{
case "click"=>
println("clicked")
case "grasp"=>
println(“grasp please”)
case "drop"=>
println("Why don we stop it here? : got from client str: "+str)
}
}.map { _ => println("Disconnected")}
val out=Enumerator("1","2","3")
(in,out)
//Tuple(Iteratee[String],Enumerator(String))
}
usingはwebsocketを作成するためのメソッド。返り値にWebSocketを返す。その他に2つほどWebSocketを返すメソッドがあって、一つがasyncメソッド。もう一つがadapterメソッド。まあ基本的にはusingで良さげだな…
def using[A]
(f: (RequestHeader) ⇒ (Iteratee[A, _], Enumerator[A]))(implicit frameFormatter: FrameFormatter[A]): WebSocket[A]
Creates a WebSocket result from inbound and outbound channels.
foreachは与えられたリソースひとつひとつに具体的な処理をしていくための関数。引数として各要素に行う処理内容とそのデータの型を受け取りIteratee[E,Unit]、つまり空のIterateeを返すのか…?
そしてmapは単純にIterateeの終了時に実行される処理を追加。具体的な処理内容である高階関数を引数とするIterateeは基本的にノンブロッキング故に常にopen。だから終了されるというこてゃ接続が切れたと捉えることができるのか。
def foreach[E](f: (E) ⇒ Unit)(implicit ec: ExecutionContext): Iteratee[E, Unit]
f ; the function, that should be executed for every chunk
returns ; an play.api.libs.iteratee.Iteratee which executes a provided function for every chunk. Returns Done on EOF.
Example:
// Get all chunks of input
def printChunks: Iteratee[String, Unit] = Iteratee.foreach[String]( s => println(s) )
Iterateeパッケージにあるsealed trait
Step[E, +A] extends AnyRefはIterateeの状態を表すためにある。このtraitは3つのサブクラスを持つ;Cont, Done, Error
Iteratee自体はそれを保持するためのfold関数を用意しており、その内部でstep関数を定義している。step関数はIterateeの結果である型とIterateeに入るInputを受け取りInputの種類によって挙動を変える。Input.EOF、つまりファイルの最後だという通知がきたらDone、Emptyなら単純に新しいContを作る、そしてElならば前回の状態を関数として値にいれそれを次の Contに引き継ぐために再帰を行っている。
def fold[E, A](state: A)(f: (A, E) => A): Iteratee[E, A] = {
def step(s: A)(i: Input[E]): Iteratee[E, A] = i match {
case Input.EOF => Done(s, Input.EOF)
case Input.Empty => Cont[E, A](i => step(s)(i))
case Input.El(e) => { val s1 = f(s, e); Cont[E, A](i => step(s1)(i)) }
}
(Cont[E, A](i => step(state)(i)))
}
Iterator, Iteratee, そしてEnumerator
Play FrameworkのIteratee, Enumeratorが最高に謎なんで現状の理解をここに記します。間違っている点を指摘してもらえると助かります。
参考にしたのは
http://qiita.com/sunny4381/items/a711fa72db26c9263b3f
http://mandubian.com/2012/08/27/understanding-play2-iteratees-for-normal-humans/
Play FrameworkにおけるIterateeとは繰り返す処理の中身のことで、ある型E
から別の型Aを生成する処理内容のこと。言わばforeachに引数として与える高階関数みたいなものでありループそのものでもあるのかな。となるとforeachそれ自体って感じ?そしてEnumeratorはコレクションに近い。
いわばEnumeratorがデータの生産者ならIterateeはその消費者ということ。
Scalaで通常使うコレクションやIteratorと何が違うかというと、まずEnumeratorはStreamだという点。StreamはListとかと違って遅延評価。
遅延評価とはその名の通りすぐさま評価されるのではなく実際に計算が必要になってから評価を行う手法。下の例ではStream(1,2,3)を作りそれをfilterにかけたり別のListと統合したりしてるわけだけど実際にその値が評価されているのはforeach以下を実行したときであってそれまでそのStreamは評価されていない。
scala> val s=1#::2#::3#::Stream.empty
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> val f=s.filter(_>2)
f: scala.collection.immutable.Stream[Int] = Stream(3, ?)
scala> val x=f++List(10,20)
x: scala.collection.immutable.Stream[Int] = Stream(3, ?)
scala> x
res0: scala.collection.immutable.Stream[Int] = Stream(3, ?)
scala> x.foreach(println)
3
10
20
scala> x
res2: scala.collection.immutable.Stream[Int] = Stream(3, 10, 20)
scala> f
res3: scala.collection.immutable.Stream[Int] = Stream(3)
scala> s
res4: scala.collection.immutable.Stream[Int] = Stream(1, 2, 3)
この遅延評価のおかげでいくらでもStreamに値を列挙することができるらしい。このEnumerator[E]は(Eは型)3つケースを保持できる。
Input[E] ; 型Eのデータの集まり
Input.Empty ; データが空
Input.EOF ; ファイルから読み込む際にファイルの終わりにきたケース?
val pizza=Pizza("Domino Pizza")
val enumerator:Enumerator[Pizza]
=Enumerator.enumInput(Input.el(pizza))
Enumeratorはただの生産者であり誰かが使ってくれるまで何もしない。さらに誰かが使うまで生産もしない。言わばレストランを予約した際に注文も事前にしておいたのに行ってみたら予約自体はできてたけど何も作ってなくて今から作りますね〜 ニコっ
みたいなものか。
次にIterateeとIteratorの違いだけど、Iteratorがコレクションから生成される
※ご指摘によると、コレクションから生成されることが多いものの必ずしもコレクションから生成されるとは限らないらしい。Playの方ではどうなってるかはちょっとわからないですけど少なくともscala標準装備の方はそんな感じとのこと。
コレクションから生成されることは多いけれど、scala標準のIteratorは、hasNextとnextを定義するだけである程度簡単に独自のIterator定義できるし、他にもIterator.continuallyやIterator.iterateというメソッドがコンパニオンに存在したりと、必ずしも「Iteratorはコレクションから生成される」とは限らないと思います
一方でIterateeはより汎用的に使うことが出来る。また、Iterateeは不変(immutable)で、非ブロック非同期処理で、入力の型 E と出力の型 A が静的に定義されているという特長に加え、結果が必要になるまで何ら実行されないという特長があるとのこと。
Iterateeがループをするにあたって以前のIterateeの状態を知らなければいかんということで(例えば各要素を足し合わした合計を求めたい時に1ステップ前の状態を知らねば単にループするだけになる)Iterateeは3つの状態を持つ。Cont,Done,Error。ContとDoneは似ていて、ContはKeep goingな感じだけどDoneはもうそろ終わるよ!みたいな。参考にしたサイトではそういう意味を込めてIterateeは単純に状態を宣言する機械だ!っていってたな。
これまでIterateeとEnumeratorはセット販売ですよ〜みたいなことを書き連ねてきたけどEnumeratorは単にあると便利なヘルパーさんで実際Iterateeさえあれば一応おっk−なんだよね。
Iteratee[E, A].feed() メソッドを利用したら実際Enumeratorを使わずに同じことが可能。下の例のようにひとつひとつIterateeに要素をつかしていけばまあEnumeratorは必要ないっちゃない。
var iter: Iteratee[Int, Int] = Iteratee.fold(0) { (total, e) => total + e }
var futureiter: Future[Iteratee[Int, Int]] = null
futureiter = iter.feed(Input.El(1))
EnumeratorはIterateeというコンセントに差し込むように使うわけだけどrunメソッドとapplyメソッドという二つの差し込み方がある。この2つはどうやら返り値が異なり、
run ; Promise[ Iteratee[E,A] ]
apply ; Promise[A]
となっている。
val itera=Iteratee.fold(0)(_+_)
val enu=Enumerator(1,2,3,4,5)
val appresult:Promise[Iteratee[Int,Int]]=enu apply itera
val runresult:Promise[Int]=enu run itera
ちなみにPromise[Iteratee]とIterateeは可逆性が保証されている。遅延にしたかったらPromise、その必要がなかったらIterateeのまんまみたいな。
大まかな輪郭を掴めたんじゃないかと信じている。