17. Collec*ons
Joongjin Bae Ameba:dudug twi;er:bae_j
Index
• Sequences – Lists, Arrays, List buffers, Array buffers, StringOps
• Sets and Maps – Using Sets and Maps, Default, Sorted
• Mutable vs. Immutable collec*ons • Ini*alizing collec*ons – Conver*ng array or list, mutable and immutable sets and maps
• Tuples
Sequences
Array Listは触れません
ListBuffer
Listは先頭からは速いが末尾からは遅い。 Listを逆にして先頭から接続するか ListBufferを利用する。 ListBufferはmutableであり、append, prepend演算(opera*on)可能 += append (ex buf += 1) +=: prepend (ex 4 +=: buf) => buf.type = ListBuffer(4,1)
ListBuffer
• buf.toListでList取得可能 • Listの代わりにListBufferを使う理由はstack overflowを回避するため – 詳細は22章で
ArrayBuffer
• ListBuffer同様、mutable, append, prepend可能 – buf += 12 – 14 +=: buf – buf.toArray => Array (14, 12)
• scala.collec*on.mutable.ArrayBuffer import必須
• buf.length => 2, buf(0) => 14 利用可能
ArrayBuffer
• 前後から接続、追加、削除可能 • Arrayのすべての操作可能、ちょっと遅い – Wrapperだから
• 追加/削除は平均O(1)(constant *me on average)がたまにO(n)になる – 配列の再構築が必要だから
StringOps
def hasUpperCase(s: String) = s.exists(_.isUpper) hasUpperCase(“Scala”) => true hasUpperCase(“scala”) => false Stringはexistsメソッドがない。 なぜ実行出来る?
StringOps
• コンパイラがs Stringを暗黙的にStringOpsへ変換し実行する
• existsメソッドはcharの配列として扱い
Sets and maps
使い方は触れません
Default sets and maps
• Set(), Map()で簡単に生成できる。 • 速いアルゴリズム(hashtable)を使ってobjectがcollec*onの中に存在するか判断
• mutable.Set(), mutable.Map()は HashSet, HashMapを生成
• immutableの場合、要素数によって違うobjectを返す
Default sets and maps
要素数 実装
0 immutable.EmptySet
1 immutable.Set1
2 immutable.Set2
3 immutable.Set3
4 immutable.Set4
5 immutable.HashSet
immutable.Set()
Default sets and maps
要素数 実装
0 immutable.EmptyMap
1 immutable.Map1
2 immutable.Map2
3 immutable.Map3
4 immutable.Map4
5 immutable.HashMap
immutable.Map()
Sorted sets and maps
• SortedSet, SortedMap提供(Trait) • 赤黒木を使ったTreeSet, TreeMapで実装されている。
mutable vs. immutable
• mutableがよく動く場合とimmutableがよく動く場合がある。
• どちを使うか迷う場合はimmutableを使う。 – 後でmutableへ変換すれば良い – サイズが小さい
mutable vs. immutable
• scalaはimmutableómutable変換しやすくするsyntac*c sugarを提供 – immutableの場合 += メソッドが定義されてない – interpreterが a += b => a = a + bに解析
+= example
val people = Set(“B”, “土橋”) people += “木本” var people = Set(“B”, “土橋”) people += “木本”
-‐= ++= 例
people -‐= “B” people ++= List(“Bae”, “Kim”) people ? immutable.Set[java.lang.String] = Set(土橋, 木本, Bae, Kim)
Ini*alizing collec*ons
• factoryメソッドの引数として渡す – List(1,2,3) – Set(‘a’,’b,’c’) – mutable.Map(“hi” -‐> 2, “there” -‐> 5)
• コンパイラが適切な型を設定する。 – List[Int] – Set[Char] – mutable.Map[String, Int]
Ini*alizing collec*ons
• この場合は? val stuff = mutable.Set(42) stuff += “abc” 最初生成時IntになっているためStringは追加できない。 解決:val stuff = mutable.Set[Any](42)
Ini*alizing collec*ons
• collec*on生成時collec*onを引数として渡したい場合
val colors = List(“red”, “blue”) val treeSet = TreeSet(colors) => error val treeSet = TreeSet() ++ colors
Conver*ng to array or list
• Just invoke toList/toArray – treeSet.toArray – colors.toArray
• toArrayの結果は? – treeSet (blue, red) – colors (red, blue)
• toList/toArrayはcollec*onのコピーなのでコストに注意
Conver*ng mutable ó immutable
treeSet => (blue, red) val mutaSet = mutable.Set.empty ++= treeSet val immutaSet = Set.empty ++ mutaSet
Tuples
• 異なるtype objectを持つ配列 – (1, “hello”, Console)
• Javaの場合複数の戻り値を返したい場合、DTO又はPairクラス等を実装する必要有り
• ScalaはTupleを使えば簡単
Tuple使い方 def longestWord(words: Array[String]) = { var word = words(0) var idx = 0 for (i <-‐ 1 un*l words.length) if (words(i).length > word.length) { word = words(i) idx = i } (word, idx) }
Tuple使い方
val longest = longestWord(“The quick brown fox”.split(“ ”) result => (quick, 1) • 結果のTupleを使う場合_1, _2を利用 – longest._1 => quick – longest._2 => 1
Tuple使い方
– val (word, idx) = longest word: String = quick idx: Int = 1
– val word, idx = longest word: (String, Int) = (quick, 1) idx: (String, Int) = (quick, 1)