今回はKotlinのMapです。JavaScriptやPHPなら連想配列、Pythonなら辞書という呼び名で馴染みがある方も多いかも知れません。そんなMapの基本をお伝えしようと思います。
Mapの特徴
まずはMapがどういったものなのか、その特徴を挙げてみます。
- 値をキー(Key)とバリュー(Value)のペアで管理する
- キーはユニーク(ただ1つ)である必要があるが、バリューは重複可
- 値のアクセスにはインデックス番号ではなくキーを指定する
つまるところ、Mapの特徴といえば「キーとバリューでの値管理」に尽きます。
Listの場合、自動的に番号が付けられた箱に値が入っている構造なのに対し、
Mapは箱自体に名前を付けて管理するイメージです。この箱に付けられた名前がキーとなります。
Mapの作成
MapもListやSetと同じようにOf関数で作成しますが、その引数は他のコレクションとは若干違いがあります。
val map = mapOf("とりあえず" to "ビール",
"3杯目" to "ハイボール",
"締め" to "ワイン")
println(map)
//{とりあえず=ビール, 3杯目=ハイボール, 締め=ワイン}
ここではリードオンリーのMap型のインスタンスを作成しています。
Mapのインスタンスを作成する際、値を代入するには(key to value,key to value)のように、 キーとバリューを「to」でつなぎ、いくつものキー、バリューペアを同時に代入していく方法をとります。
Mapの中身はPair型
同じような形で値を代入する型にPair型があります。
ここでは詳しくは取り上げませんが、2つの値をまとめて1つの変数に代入できる、Pair型という型があるということは、覚えておいて損はありません。
型パラメータを明示してPair型のインスタンスを作成してみます。
val month: Pair<Int,String> = 1 to "January"
もしくはPairクラスのコンストラクタで、
val month = Pair(1,"January")
これでも同じ結果となります。
ここでMapの型パラメータを覗いてみると、
んーそっくり。つまりMapの内部構造はPair型のListとも言えるわけです。
このPair型、面白いのは1つのインスタンスから、2つの変数に同時に値を代入できるというところでしょう。
val (x,y) = month
この場合Pair型の最初の値である1がxに、次の"January"がyにそれぞれ代入されます。
Mapでもこのような挙動を扱うことが多いので、若干蛇足ではあるかも知れませんがご紹介しておきました。
値へのアクセス
Mapでは他のコレクションと違い、インデックス番号ではなく、キーによってバリューにアクセスします。
println(map["とりあえず"]) //ビール
ただし、バリューでキーを呼び出すことはできません。
println(map["ビール"]) //null
"ビール"というキーは無いので、返答はnullとなります。
全ての要素を出力するプロパティ
keys、valuesプロパティで全てのキー、バリューを出力できます。要素数はお馴染みのsizeプロパティです。
println(map.keys) //[とりあえず, 3杯目, 締め]
println(map.values) //[ビール, ハイボール, ワイン]
println(map.size) //3
MutableMap
他のコレクションと同様、Mapにもリードオンリーと変更可能の2種類があります。変更可能のMapを作成してみましょう。
val mMap = mutableMapOf<Int,String>()
値無しで作成することももちろん可能ですが、その場合は型パラメータを明示しておきます。
値の追加
このMutableMapに値を追加するには複数の方法があります。
mMap[1] = "枝豆"
mMap.put(2,"唐揚げ")
mMap += 3 to "牛とろとろ煮"
println(mMap)
//{1=枝豆, 2=唐揚げ, 3=牛とろとろ煮}
1行目ではキーをインデックスのように扱い、=の左辺でキー、右辺でバリューを登録しています。
2行目のように、putメソッドでキーとバリューを追加することも可能です。ただIntelliJではputメソッドによる追加は推奨されるものでは無いらしく、使用には問題ありませんが警告が出ます。
3行目では+=演算子で追加しています。この場合は新規作成したときと同じように、キーとバリューをtoでつなげて登録しましょう。
どの方法でも既に同じキーが存在している場合、そのバリューを上書きします。
複数のキー、バリューペアを追加する
上記の+=演算子や、putAllメソッドを使用することで、複数のペアをMapに追加することができます。
mMap += mapOf(1 to "枝豆",
2 to "唐揚げ",
3 to "牛とろとろ煮")
mMap.putAll(listOf(4 to "サラダ",
5 to "揚げ出し"))
下のputAllではListを追加していることに注目してみてください。
複数の値を追加する場合、追加する型はMapでもListでもかまいません。Listを選択した場合、追加する型はList<Pair<Int,String>>となります。
値の削除
値を削除するにはremoveメソッドを使用します。
mMap.remove(1)
mMap.remove(2,"唐揚げ")
println(mMap)
//{3=牛とろとろ煮}
キーだけを指定しても、キーとバリュー両方指定してもかまいません。
両方指定した場合、バリューの指定が実際と違っていれば、そのremoveは無視されます。
全要素の削除
Mapの全ての要素を削除する場合はclearメソッドを使用します。
mMap.clear()
これも他のコレクション同様、引数無しのメソッドです。Mutable〇〇にしか使えませんので注意しましょう。
Mapのループ処理
最後にループ処理です。扱う値が2つになる以外は、ListやSetと変わりありません。
for((k,v) in mMap){
println("${k}品目は$v")
}
for文ではMapの各要素をk(キー)とv(バリュー)2つのローカル変数に分けて処理しています。
forEachでも基本的には同じです。ラムダ式の引数が2つになるので、->も記述しましょう。
mMap.forEach{(k, v)->println("${k}品目は$v")}
ただforEachでは引数をMap自体として、itで参照することもできます。
mMap.forEach{println("${it.key}品目は${it.value}")}
その場合はmap.key、map.valueとすることで、キーやバリューにアクセスできます。
おさらい
今回はMapの基本として、
- Mapの特徴
- 作成方法
- Mapの中身の型
- 値へのアクセス方法
- MutableMapへの値の追加と削除
- Mapのループ処理
以上のことについてお伝えしました。なおMapやMutableMapから呼び出せるメソッドは別記事でまとめているので、メソッドについて知りたい方はそちらをご覧ください。