読者です 読者をやめる 読者になる 読者になる

新人SEの学習記録

14年度入社SEの学習記録用に始めたブログです。気づけば社会人3年目に突入。

学習記録:Scala逆引きレシピ

学習記録 Scala 関数型 プログラミング

第5章:コレクション

コレクションの基礎

Scalaのコレクション

Scalaには標準で強力なクラスライブラリが用意されています。
コレクションは以下の3種類に大別されます。

  • Seq:順序を持った要素の集合
    • Vector
    • List, Stream
    • ListBuffer, ArrayBuffer
  • Set:重複を含まない要素の集合
    • TreeSet
    • HashSet
  • Map:キーバリューペアの集合
    • TreeMap
    • HashMap

コレクションは、通常ファクトリメソッドを使用する。その際、型は省略してよい。

var list: List[String] = List[String]("A", "B", "C")
// 型、パラメータ型を省略
var list = List("A", "B", "C")

Scalaのコレクションは基本的にイミュータブルであり、一度インスタンスを生成すると要素の追加や変更、削除は行えない。
これらを行う場合、新たなインスタンスを生成する必要がある。
また、要素を動的に追加したい場合は、scala.collection.mutableパッケージのミュータブル版コレクションクラスを使用する。

なお、Scalaのコレクションは共変=型パラメータで指定した型のサブクラスのコレクションも代入できる。
ex) List[AnyRef]にStringの要素を代入可能

コレクションの比較・変換

==および!=メソッドで比較できる。比較するのは、

  • コレクションの種類が同じか
  • コレクションが同じ要素を持つか
  • Seqの場合、要素が同じ順序で並んでいるか

で、全て満たす場合「等しい」とみなされる。

コレクション同士の相互変換を行うには、以下のメソッドを使用する。

  • toArray
  • toIterable
  • toSeq
  • toList
  • toSet
  • toMap
  • ...

List

基本的な使い方

生成には前述のファクトリメソッドを使用する。

var list: List[String] = List[String]("A", "B", "C")
var list = List("A", "B", "C")
メソッドを使って連結し、インデックスで要素にアクセスする。
val list = "A" :: "B" :: Nil
val ele1 = list(0)
val ele2 = list(1)
主なメソッド

Listの主なメソッドは以下の通り。

メソッド 説明
::、+: 先頭に要素を追加
:+ 末尾に要素を追加
:::、++、++: Listを連結
size Listのサイズを取得
isEmpty/nonEmpty 空/空でないかどうかを返す
head/last 先頭/末尾の要素を取得
foreach 要素を繰り返し処理
filter/filterNot 要素をフィルタリングする
map/collect 要素を変換する/条件に一致した要素に対してmap処理する
sorted/sortWith, sortBy 自然順序付けの昇順/任意の条件でソートする
tail/init 先頭/末尾の要素を除いたListを取得する
slice/take/drop [指定範囲の/先頭から指定個数を選択した/先頭から指定個数を除外した]要素を取得する
contains/exists/forall 指定要素が含まれているか/指定条件を満たす要素が含まれているか/全要素が指定条件を満たすか
reduceLeft/reduceRight Listの要素を左/右側から順に集計する
foldLeft/foldRight 初期値を指定してListの要素を左/右側から順に集計する
zip/unzip 2つのListをマージして各Listの要素をタプルに持つListを作成/分解する
配列との使い分け
  • Listは先頭から順に辿るため検索が遅い=先頭の要素への操作が多いor要素を順番に処理する場合
  • 配列は特定要素へのアクセスが高速=特定のインデックスへのアクセスが多い場合

という感じにすると良い。

Map

基本的な使い方

Mapの生成方法は以下の通り。

val map = Map("key1" -> "value1", "key2" -> "value2")

値を取得するには、get/getOrElse/apllyメソッドを使用する。

val map = Map("key1" -> "value1", "key2" -> "value2")

// Option型で取得する。キーがない場合はNone
val get1 = map.get("key1") // => Some("value1")
// キーがない場合の初期値を指定する
val getoe1 = map.getOrElse("key1", "") // => "value1"
val getoe3 = map.getOrElse("key3", "") // => ""
// 値を直接取得する。キーがない場合NoSuchElementExceptionが発生
val apply1 = map("key1") // => "value1"
主なメソッド
メソッド 説明
get/getOrElse/apply 値を取得する。詳細は上参照
+/- 要素を追加する/キーを指定して要素を削除する
++/-- Mapを連結する/キーのListを指定して複数要素をまとめて削除する
size サイズを取得する
isEmpty/nonEmpty 空かどうか/空でないかどうかを調べる
filter/filterNot 要素をフィルタリングする
foreach キーと値のペアを繰り返し処理する
keys/values キー/値を返すIterableを取得する
contains 指定したキーがMapに含まれているかどうか調べる
補足

なお、Mapの要素はキーと値のタプルである。
"->" は2つの要素を持つタプルを生成するためのメソッドで、以下の記述は同じ意味になる。

val map = Map("key1" -> "value1", "key2" -> "value2")
val map = Map(("key1", "value1"), ("key2", "value2"))

Set

基本的な使い方

Listと違い、インデックスを指定して要素にアクセスはできないが、それ以外は概ねListと同様に扱うことができる。
また、Setは値の重複を許さないため、重複した要素を追加しても無視される。

val set: Set[String] = Set("A", "B", "C")
val set2 = set + "D"
val set3 = set2 ++ Set("E", "F")
メソッド 説明
+/++ 要素を追加する/複数要素をまとめて追加する
-/-- 要素を削除する/複数要素をまとめて削除する
&/ 2つのSetのAND/ORを取得する
size サイズを取得する
isEmpty/nonEmpty 空かどうか/空でないかどうかを調べる
filter/filterNot 要素をフィルタリングする
foreach 要素を繰り返し処理する
contains 指定したキーがSetに含まれているかどうか調べる

その他のコレクション

Vector

Vectorの使用法はListとほとんど同じだが、ランダムアクセスが高速という特徴を持つ。

val vector = Vector("A", "B", "C")

// インデックスが1の要素を*に置換
val newvector = vector.updated(1, "*")
Tuple

Tupleは、複数の値を1つのデータとして扱うためのコンテナである。
メソッドの戻り値として複数の値を返したい場合や、クラスを作るまでもないデータを使う場合などに便利。
任意の数の要素を丸括弧で囲むことで作成でき、要素が2つ/3つの場合はPair/Tripleという別名でも作成できる。

val user: (Int, String) = (1, "Hoge")
val book: (String, String, Int) = ("Title01", "Publisher01", 3000)

// 値を取得
val id = user._1
val name: String = user._2

// 値を分解
val (bookName: String, publisher: String, price: Int) = book
Stream

Streamは、Listと同じく順序を持った要素の集合を扱うが、要素が遅延評価されるという違いがある。
一度に全ての要素を読み込むと大量のメモリを消費してしまうような場合や、要素数が無限のリストを扱う場合に使う。

// Streamを生成。2番目以降の要素はまだ評価されない
val stream1 = Stream("A", "B", "C") // => Stream("A", ?)
// 巨大なコレクションを生成してもエラーにならない(ListだとOutOfMemory)