object Main {
def main(args: Array[String]): Unit = {
// 順序のあるコレクション
// Traversable -> Iterable -> Seq
// -> List
// -> Array
// -> Buffer -> ListBuffer, ArrayBuffer
// -> Vector
// -> Stream
val list = List(1, 2, 3)
// マップ
// Traversable -> Iterable -> Map
val map = Map("a" -> 1, "b" -> 2)
// 集合
// Traversable -> Iterable -> Set
val set = Set(1, 2, 3)
// 相互変換 (マップのみタプルが絡むため特殊)
println(map.toList) //=> List((a,1), (b,2))
println(map.toList.toMap) //=> Map(a -> 1, b -> 2)
println(list.toIterable) //=> List(1, 2, 3)
println(list.toSeq) //=> List(1, 2, 3)
println(list.toList) //=> List(1, 2, 3)
println(list.toArray) //=> [I@35a9cc1a
println(list.toSet) //=> Set(1, 2, 3)
// 生成元がミュータブルであっても、結果はイミュータブルになります。
val mapImmutable = scala.collection.mutable.Map(1 -> 10).toMap
// mapImmutable += (2 -> 20) // エラー
}
}
基本的なリストの操作は『Scala の基本文法』に記載したとおりです。それ以外にも以下のような操作ができます。
object Main {
def main(args: Array[String]): Unit = {
val list = List(1,2,3)
for(e <- list) {
println(e)
}
list.foreach{ e =>
println(e)
}
}
}
object Main {
def main(args: Array[String]): Unit = {
println(List(3,1,2).sorted) //=> List(1, 2, 3)
println(List("abc", "ab").sortWith{ (x, y) => x.length < y.length }) //=> List(ab, abc)
println(List("abc", "ab").sortBy{ _.length }) //=> List(ab, abc)
}
}
object Main {
def main(args: Array[String]): Unit = {
// ruby の flatten のようなものです
println(List(List(1,2),List(3)).flatten) //=> List(1, 2, 3)
println(List(1,2,3).flatMap { e => // とすると、
List(e, e)
})
//=> List(1, 1, 2, 2, 3, 3)
println(List(1,2,3).map { e => // これと同じ意味。
List(e,e)
}.flatten) // 中間 List も生成せずに高速
//=> List(1, 1, 2, 2, 3, 3)
// Option 型のリストから None を除外する効果
println(List(Some("a"), Some("b"), None).flatten) //=> List(a, b)
}
}
object Main {
def main(args: Array[String]): Unit = {
val list = List(1,2,3)
println(list.mkString) //=> 123
println(list.mkString("delimiter")) //=> 1delimiter2delimiter3
println(list.mkString("pre", "delimiter", "post")) //=> pre1delimiter2delimiter3post
}
}
object Main {
def main(args: Array[String]): Unit = {
// ruby の inject のようなものです
println(List("b", "c").foldLeft("a") { (l, e) =>
l + e
}) //=> abc ("a" は l の初期値)
println(List("a", "b").foldRight("c") { (e, r) =>
e + r
}) //=> abc ("c" は r の初期値)
// (("a" + "b") + "c")
println(List("a", "b", "c").reduceLeft { (l, e) =>
l + e
}) //=> abc
// ("a" + ("b" + "c"))
println(List("a", "b", "c").reduceRight { (e, r) =>
e + r
}) //=> abc
// リストが空 List() の場合に例外を投げたくない場合
println(None.reduceLeftOption { (l: Any, e: Any) =>
}) //=> None
println(List(1,2,3).reduceRightOption { (e: Int, r: Int) =>
e + r
}) //=> Some(6)
}
}
object Main {
def main(args: Array[String]): Unit = {
// 条件式 (true/false) で二つのリストに仕分け
println(List(-1,2,-3).partition{ _ > 0 }) //=> (List(2),List(-1, -3))
// 式の結果で複数のリストに仕分け
println(List(-1,2,-3).groupBy{ _ > 0 }) //=> Map(false -> List(-1, -3), true -> List(2))
// インデックス番号 i で二つのリスト (0..i-1, i..-1) に分割
val (listA, listB) = List("a", "b", "c").splitAt(2)
println(listA) //=> List(a, b)
println(listB) //=> List(c)
}
}
object Main {
def main(args: Array[String]): Unit = {
// ruby の each_with_index のようなものです
List("a", "b", "c").zipWithIndex.foreach{ tuple =>
println(tuple) //=> (a,0), (b,1), (c,2)
}
// 長さが一致しない場合、超過した要素は捨てられます
val zipped = List(1,2,3,4).zip(List("a", "b", "c"))
val unzipped = zipped.unzip
println(zipped) //=> List((1,a), (2,b), (3,c))
println(unzipped) //=> (List(1, 2, 3),List(a, b, c))
}
}
昔、数学 A で出会った集合です。
object Main {
def main(args: Array[String]): Unit = {
val set = Set(1,2,3)
// 要素の追加
val set2 = set + 4
println(set2) //=> Set(1, 2, 3, 4)
println(set2 + 4) //=> Set(1, 2, 3, 4) (重複して追加はされない)
// 要素の削除
println(set - 1) //=> Set(2, 3)
println(set - 0) //=> Set(1, 2, 3) (存在しない要素を指定してもエラーにはならない)
println(set.filter{ _ != 1 }) //=> Set(2, 3)
// 和集合
println(set | Set(4,5,6)) //=> Set(5, 1, 6, 2, 3, 4) ←(A ∪ B)
println(set ++ Set(4,5,6)) // としても Set では同じ意味
// 積集合
println(Set(1,2) & Set(2)) //=> Set(2) ←(A ∩ B)
// 差集合
println(set -- Set(1)) //=> Set(2, 3)
// 走査
set.foreach{ e =>
println(e) //=> 1 => 2 => 3
}
// 変換
println(set.map{ _ * 2 }) //=> Set(2, 4, 6)
}
}
他の言語の連想配列のようなものです。
object Main {
def main(args: Array[String]): Unit = {
val map = Map[Int, Int](1 -> 10, 2 -> 20)
// 値の取得
println(map.get(1)) //=> Some(10)
println(map(2)) //=> 20 (ただし、存在しないキーを指定すると例外)
println(map.getOrElse(0, -1)) //=> -1
// マップはタプルのリストのようなもの
val tuple1 = (1, 10)
val tuple2 = (2, 20)
val map2 = Map(tuple1, tuple2) // 1 -> 2 は (1, 2) というタプルを生成する記法
println(map2) //=> Map(1 -> 10, 2 -> 20)
// 要素の追加
val map3 = map + (3 -> 30, 4 -> 40)
println(map3) //=> Map(1 -> 10, 2 -> 20, 3 -> 30, 4 -> 40)
// マップの連結
println(Map(1->10) ++ Map(2->20)) //=> Map(1 -> 10, 2 -> 20)
// 要素の削除
println(Map(1->10, 2->20) - 1) //=> Map(2 -> 20)
println(Map(1->10, 2->20, 3->30, 4->40) - (1,3,4)) //=> Map(2 -> 20)
println(Map(1->10, 2->20, 3->30, 4->40) -- List(1,3,4)) //=> Map(2 -> 20)
println(Map(1->10,2->20).filter{ case(key,value) =>
key == 2
}) //=> Map(2 -> 20)
// 走査
map.foreach{ e =>
println(e._1 + e._2) //=> 11 => 22 (タプルのループ)
}
map.foreach{ case(key, value) =>
println(key + value) // としても同じ
}
println(map.keys) //=> Set(1, 2)
println(map.values) //=> MapLike(10, 20)
// 長さ
println(map.size) //=> 2
// 含まれるか、空かどうか
println(map.contains(0)) //=> false
println(map.isEmpty) //=> false
println(map.nonEmpty) //=> true
// 変換 (map の map と書くと混乱する)
println(Map(1->10, 2->20).map{ case(key,value) =>
(key, value * 2)
}) //=> Map(1 -> 20, 2 -> 40)
println(Map(1->10, 2->20).map{ case(key,value) =>
key
}) //=> List(1, 2)
// ソート (キーを List に変換してソート)
val sortedKeys = map.keys.toList.sorted
sortedKeys.foreach{ key =>
println(map(key)) //=> 10 => 20
}
}
}
参考: 具象不変コレクションクラス
ストリーム (Stream) はリストに似ているが、要素は遅延評価される。そのため、ストリームは無限の長さをもつことができる。呼び出された要素のみが計算される。他の点においては、ストリームはリストと同じ性能特性をもつ。
object Main {
def main(args: Array[String]): Unit = {
// a, b, a+b, b+(a+b),...
def fibFrom(a: Long, b: Long): Stream[Long] = {
a #:: fibFrom(b, a + b) // ストリームの先頭への要素の追加
}
val fibs = fibFrom(1,1) // 無限長
println(fibs) //=> Stream(1, ?)
for(i <- 0 to 10) {
println(fibs(i))
}
// リストでは実現できません。
def fibFromList(a: Long, b: Long): List[Long] = {
a +: fibFromList(b, a + b) // リストの先頭への要素の追加
}
// val fibsList = fibFromList(1,1) // 無限長リストは無限にメモリを必要とする
//=> java.lang.StackOverflowError
}
}