のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

Scalaマスターになりたくて ~コレクション(array, list, tuple, set, map)の基本~

はじめに、Scalaはすごい

勉強するごとに感じる。 先日も会社の先輩にScalaで書いたコードを見せて頂いのだが、まるで自分の書いたものとは違った。 Scalaという名前には「スケーラブルに開発者のレベルに応じて進化する」という意味があるが、まさにそのとおりだと感じた。 他の言語でももちろんメタ的な属性や、様々な組み込み関数を駆使することで開発者のレベルによって差が出るものではあるが、全然読めない…とはならない。 少なくとも私の使用しているPythonではそんなことはない。 しかしScalaの場合は「全く読めない」のだ。(それが会社でただしいかどうかは別にして)これは非常に面白い言語だと感じる理由の一つだった。 自身のレベルアップを如実に感じることができる言語、それがScalaだ。

書籍はもちろんコップ本と参考に記載するいくつかのサイトを使用させて頂いている。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

  • 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
  • 出版社/メーカー: インプレス
  • 発売日: 2016/09/20
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (1件) を見る

しょうもないことについてもざっくりメモをとって本が無くても見てわかるようなものにする&知識の定着が目的である。

Scalaのコレクションのimutableとmutable

Scalaのコレクションも他の言語と同様に基本のコレクションとして以下がある。(もちろん他にもある)

  • Array,List
  • tuple
  • Set -Map

全てのコレクションの体系は参考にURLに詳しく記載があるため確認すると良い。

以前の記事で、Scalaは命令型と関数型の両方を使用できる言語だと説明したが、それを両立させるための手段として各コレクションにおいて「imutable」(不変)と「mutable」(可変)なものを持っている。 (正確にはそれらの基底クラスとなるscala.collectionも持っているが、おそらくこれを使うケースはあまりないのでは?と思う。) そしてScalaでは関数型を推奨していることもあり、デフォルトで使用するコレクションは基本的に「imutable」となる。例えばmutableなものを使用したいときは以下のように明示的にimportしてあげる必要がある。

import scala.collection.mutable

早速以下で簡単にScalaのコレクションの使用方法について見ていこう。

配列(ArrayとList)

ちょっと最初私も混乱した点として、ArrayとListの存在がある。 これらは先に述べた「imutable」と「mutable」なコレクションを別の名前のコレクションとして保持している。 Array=mutableList=imutableである。 なぜ別の名称がついているのが私はまだわかっていないが、おそらく本質的に異なるコレクションなのだと思う。(だとすると上記の説明では語弊があるかもしれない。 しかし、基本の使い方には大きな差異はないので、基本的な使用の仕方では強く意識する必要はなさそうだ。各スタイル、つまり関数型ならList、命令型ならArrayというように使い分ければいいだろう。

宣言と初期化

  • new キーワードを使った配列の宣言 初期化しない宣言はmutableなコレクションしかできないため、Array専用の宣言方法となる。(List)は以降のnewキーワードを使用しない宣言で行う。
//固定長(長さ3)の配列
val fixedLengthList = new Array[String](3)

初期化をしたい場合、こちらの書き方でも宣言が可能である。 Listの場合はこれによって宣言を行う必要がある。

val initializedArray = Array("value1" ,"value2")
val initializedList = List("value1", "value2")

基本的には型推論があるため不要だが、型を明示するときは以下のようにする。

val initializedArray :Array[String] = Array("value1", "value2")
val initializedList :List[String] = List("value1", "value2")

要素の参照(呼び出し)

要素の呼び出しはJavaとは違い、()による呼び出しを行う。

>> ArrayTest.scala
val testArray = Array("test", "name")
println(testArray(1))

ちなみにリストの場合も同様に以下で呼び出せる。

val testList = List("test", "name")
println(testList(1))

ここでprintln()print()の違いは、前者は末尾に改行が付き、後者はつかないという違いがある。 実行すると以下の結果が得られる。

$ scala ArrayTest.scala
name

ちなみに先程述べた、

要素の呼び出しはJavaとは違い、()による呼び出しを行う。

これはScalaの性質上重要な意味があるため別記事にてまとめる。

tuple(タプル)

tupleもimutableなオブジェクトであるがリストとは明確に異なる点がある。 それは要素に異なるデータ型を混在させることができる点である。

実はListも異なるデータ型を混在させて定義させることはできるのだが、この場合型推論ではList[any]として推論する。 書籍で上記の説明をしているのはanyとすることを問題としてのことなのかはわかっていない。

宣言

tupleの宣言は簡単で、()内で,で区切ることで宣言ができる。

val testTuple = ("value" , 100)

値の参照(呼び出し)

tupleのややこしいところは、インデックスが1オリジンであることである。 (Haskell等の定義を受け継いでいるらしい)

val exTuple = ("value" , 100)
println(exTuple._1)
println(exTuple._2)

実行結果

$ scala TupleTest.scala
value
100

Set(集合)

宣言

Setに関しては冒頭で説明したとおり、imutableがデフォルトでmutableなSetに関してはimportして使用する必要がある。

//imutableなSet
val exSet = Set("value1", "value2")

//mutableなSet
import scala.collection.mutable
val mutableSet = mutable.Set("value1", "value2")
// 要素の追加が可能
mutableSet += "value3"

値の参照(呼び出し)

Setは内部の要素を指定して呼び出すようなメソッドを持っていない。 集合としての用途として.contains()等使用する。

>>ExSet.scala
 val exSet = Set("value1", "value2")
println(exSet)
println(exSet.contains("value3")

val mutableSet = mutable.Set("value1", "value2")
mutableSet += "value3"
println (mutableSet)
println(mutableSet.contains("value3"))

実行結果

scala exSet.scala
Set(value1, value2)
false
HashSet(value2, value1, value3)
true

map(マップ)

宣言

mapもset同様mutableはimportして使用する。 imutableなmapは初期化で値を宣言する。

// imutableなmap
val exMap = Map("name" -> "nooozui", "id" -> "ex")

// mutableなmap
import scala.collection.mutable
val mutableMap = mutable.Map[String, String]()
mutableMap += ("name" -> "nooozui")
mutableMap += ("id" -> "ex")

値の参照(呼び出し)

mapは連想配列なので配列(array, list)と同様に(key)で呼び出すことができる。

>>exMap
val exMap = Map("name" -> "nooozui", "id" -> "ex")
println(exMap("name"))
println(exMap("id"))

実行結果

scala exMap.scala
nooozui
ex

終わりに

一通り宣言方法について学んだ。 Pythonを最初に使い始めた自分にとってはArray等の区別の違い等に混乱する部分が多かったので、今回の勉強で基本は整理できたと思う。 実際にはこれら様々な協力なメソッドが存在するのでそれらも別途まとめていきたい。

参考

docs.scala-lang.org