カテゴリー
Kotlin言語

ゼロから始めるAndroidアプリ(Kotlin編)Unit3 – 1 第1~2回 前半:コレクション(List , Set , Map)

Android Developers > スタートガイド > Kotlin と Android をゼロから学ぶ > Unit3 – ナビゲーションUnit3-1 第1回~第2回 前半 の内容をまとめたものです(翻訳ではありません)


Unit3 – 1 の内容

Unit3 – 1 では、アプリで複数のアクティビティを使えるようにします

  • アプリに用意されたいくつもの画面を、何も考えずに自然に操作できるような使用感(ユーザビリティ)を実現しようと思います
  • アプリに2つめのアクティビティを追加します
  • アクティビティを使うにはインテント(intent)を使用します
  • 複数のアクティビティの間を行ったり来たりするために、アクティビティのライフサイクルを理解します

Unit3 – 1 第1回~第2回 前半

第1回~第2回 前半 の内容は以下の通りです

  • 第1回は動画(英語)での紹介なので観なくても大丈夫です
  • Kotlin に用意されているコレクション(リスト,セット,マップなどのデータ構造)を理解します
  • リスト(list)について復習します
  • セット(set)について説明します
  • マップ(map)について説明します
  • コレクションを操作する関数の説明をします

コレクションについて

データを何らかの形でまとめたものをコレクション(collection)とかコンテナ(container)っていうの

  • コレクションは関連のある項目をまとめたものです。単語のリスト、従業員データの集合みたいなものをいいます
  • Kotlin のコレクションにはリスト(list), セット(set), マップ(map)があります
  • コレクションには、項目に順番があるもの、順番がない(順番が関係ない)ものがあります
  • コレクションには、項目が重複していても構わないもの、絶対に重複しないものがあります
  • コレクションには、項目の変更が可能なもの(mutable)、変更が不可能なもの(immutable)があります
  • コレクションのひとつ、リスト(list)については以前のチュートリアルで既に出ています。リストの項目には順番があり、データは重複しても構いません
  • Kotlin には項目を追加・削除したり、コレクションを表示したり操作したりするための様々な関数があります

リスト(list)について

リストは Unit2 – 2 第1~2回 前半 で出てきたかも

うん、とりあえずデータを並べて順番どおりにまとめたものがリストなの

数値のリストを作って表示してみます

fun main() {
    val numbers = listOf(0, 3, 8, 4, 0, 5, 5, 8, 9, 2)
    println("list:   ${numbers}")
}

ソートして表示するには次のようにします

println("sorted: ${numbers.sorted()}")

セット(set)について

セットって今月の新刊一覧みたいなかんじかな?

うん、何冊入荷していても新刊一覧に載るのは1タイトルあたり1つだけなのね

  • セット(集合)はリストと違い、項目の重複を認めません
  • 順番は問題になりません
  • セットには、ある項目データがあるかないかだけが保存されています
  • セットは数学の集合と同じように、intersect() で集合の積(∩)、union() で和(∪)をとることができます

リストからセットを作成して、それを表示します

fun main() {
    val numbers = listOf(0, 3, 8, 4, 0, 5, 5, 8, 9, 2)
    println("list:   ${numbers}")
    println("sorted: ${numbers.sorted()}")

    val setOfNumbers = numbers.toSet()
    println("set:    ${setOfNumbers}")
}

実行するとこんな感じになります

list:   [0, 3, 8, 4, 0, 5, 5, 8, 9, 2]
sorted: [0, 0, 2, 3, 4, 5, 5, 8, 8, 9]
set:    [0, 3, 8, 4, 5, 9, 2]

ミュータブル(mutable)セットとイミュータブル(immutable)セット

書き換えできちゃうのと、できないのがあるんですね

mutable set(変更可能なセット)と immutable set(変更不可なセット)を順番を変えた要素で定義して、2つのセットが同じとみなされるのかどうか試してみます

fun main() {
    val set1 = setOf(1,2,3)
    val set2 = mutableSetOf(3,2,1)

    println("$set1 == $set2: ${set1 == set2}")
}

実行結果はこんな感じになります

[1, 2, 3] == [3, 2, 1]: true
  • set1 は mutalble 、set2 は immutable で、それぞれ順番の違う要素を持っています。これらは全く同じ要素のセットで出来ているので等しいと判定されます(セットに順番は関係ありません)
  • セットでは contains() を使って特定の要素がセットに含まれているかどうか調べることができます。contains() は以前のチュートリアルでリストに使っています
  • セットに 7 が含まれているかどうか表示するにはこのようにします
println("contains 7: ${setOfNumbers.contains(7)}")

セットを使ったサンプル(まとめ)

fun main() {
    val numbers = listOf(0, 3, 8, 4, 0, 5, 5, 8, 9, 2)
    println("list:   ${numbers}")
    println("sorted: ${numbers.sorted()}")
    val setOfNumbers = numbers.toSet()
    println("set:    ${setOfNumbers}")
    val set1 = setOf(1,2,3)
    val set2 = mutableSetOf(3,2,1)
    println("$set1 == $set2: ${set1 == set2}")
    println("contains 7: ${setOfNumbers.contains(7)}")
}

マップ(map)について

マップはキー(key)と値(value)が必ずセットなの

注文番号と注文商品って感じかも

  • マップ(map)はディレクトリ(directory)とも言います
  • マップはキー(key)と値(value)がセットになったものです
    • マップはペアになったデータに便利です
    • キーを使って値がマップされていて、ペアになったデータをキーによって識別します
  • キーには重複がありません。すべてのキーが必ず1つの値に結び付けられています
  • 値は重複しても構いません
  • マップに保存する値は、文字列、数値、オブジェクト、あるいはリストやセットといったコレクションなど、なんでも構いません

ミュータブル(mutable)マップを作成する

マップも書き換えできるのと、できないのがあるんですね

名前と年齢を設定した mutableマップを作成してみます

fun main() {
    val peopleAges = mutableMapOf<String, Int>(
        "Fred" to 30,
        "Ann" to 23
    )
    println(peopleAges)
}
  • キーが文字列(String)、値が整数(Int)になっています
  • 実行すると次のようになります
{Fred=30, Ann=23}

マップにデータを追加する

追加もできるし…

マップにデータを追加するには次のようにします

peopleAges.put("Barbara", 42)

こんな風に書いてもデータを追加できます

peopleAges["Joe"] = 51

まとめるとこんな感じのコードになります

fun main() {
    val peopleAges = mutableMapOf<String, Int>(
        "Fred" to 30,
        "Ann" to 23
    )
    peopleAges.put("Barbara", 42)
    peopleAges["Joe"] = 51
    println(peopleAges)
}

実行するとこんな感じになります

{Fred=30, Ann=23, Barbara=42, Joe=51}

マップのデータを更新する

更新もだいじょうぶ

  • 同じキー(既にマップの中に存在するキー)で値を追加しようとすると、値が更新されます
  • たとえば上のコードに次のような行を追加してみます
peopleAges["Fred"] = 31

実行結果はこうなります

{Fred=31, Ann=23, Barbara=42, Joe=51}

コレクションを操作する

Kotlin にはコレクションを操作する関数が最初からいろいろ用意されてるの

  • コレクション同士はそれぞれ違った特徴をもっているけれども、共通した振る舞いをみせる点もたくさんあります
  • ミュータブル(mutable)なものは追加や削除ができます
  • すべて書き出したり、特定の要素だけ取り出したり、違うタイプのコレクションに変換したりすることもできます( toSet() を使って List を Set に変換するなど)
  • コレクションで使える便利な関数をいくつか紹介します

forEach()

for よりも簡単に書けちゃうんですね

  • コレクションをループ処理するのに for を使うことができます
  • たとえば for (項目 in コレクション) { 処理 } のようにします
  • コレクションの処理では for のかわりに forEach() を使うこともできます
  • forEach() は for と同じように、すべての項目を順に取り出して処理していきます
  • こんな風に使います
peopleAges.forEach { print("${it.key} is ${it.value}, ") }
  • for のループに似ていますがもうちょっとコンパクトです
  • 項目に変数を指定する代わりに、forEach では it という識別子を使います
    • キーは it.key , 値は it.value で参照できます
  • forEach() はメソッドですが、forEach を使うときに ( ) を付ける必要はありません。forEach { 処理 } のように記述することができます
    • forEach({ 処理 }) のように書いても動作します
  • forEach() の処理部分の書き方をラムダ式といいます。ラムダ式については以下のページに説明があります。また次回のチュートリアル(Unit3 – 1 第3回)でも説明しています

コードを実行するとこんな感じに出力されます

Fred is 31, Ann is 23, Barbara is 42, Joe is 51,
  • だいたいいい感じですが、最後にコンマが付いてしまうのがちょっと気になります
  • つぎの map() を使った処理でコンマが付かないように出力してみます

map()

項目を書き換えた新しいコレクションを作れるの

  • map() 関数(紛らわしいんですがコレクションの map とは別です)は、コレクションの項目を指定した処理で変換してコレクションの形で返します
  • forEach の代わりにこんな風に書いてみます
println(peopleAges.map { "${it.key} is ${it.value}" }.joinToString(", ") )

実行するとこんな感じになります

Fred is 31, Ann is 23, Barbara is 42, Joe is 51
  • 余分なコンマが付かなくなりました
  • map() 関数は、コレクションの項目を取り出して { } の処理をしたうえで新しいコレクションを作成して返します
    • map({処理}) なんですが、map{処理} と書いて構いません
    • コレクションの項目は it で参照できます
    • キーは it.key , 値は it.value で参照できます
    • map() 関数によって項目が文字列に変換されたコレクションが返されます
  • joinToString(“,”)は、コレクションをコンマをセパレータ(区切り文字)として各項目を並べた文字列に変換します
  • コレクションに対する処理はドット(.)を使ってチェーン状につなげて処理しています

filter()

条件に合う項目だけに絞ったコレクションが作れるの

  • filter() もコレクションでよく使う関数です
  • ある条件に一致する項目を探すのに使います
  • filter() は指定された条件に一致した項目をコレクションにして返します
  • filter({処理}) ですが、filter{処理} と書いて構いません
  • 各項目を it で参照できるのも、it.key , it.value の使い方もforEach() や map() と同じです
  • たとえばこんな風に記述します
val filteredNames = peopleAges.filter { it.key.length < 4 }
println(filteredNames)

実行すると次のようになります

{Ann=23, Joe=51}
  • このコードでは、キーとなる文字列の長さが 4 よりも短いものを抽出しています
  • 戻り値はマップ(LinkedHashMap)型です
  • マップ(コレクション)に対する処理を追加したり、リストのようなほかのコレクションに変換したりすることもできます

まとめ

Kotlin のコレクション、どんどん使ってみてくださいね

  • コレクションは関連のある項目をまとめたものです
  • コレクションには変更が可能なミュータブル(mutable)と変更できないイミュータブル(immutable)があります
  • コレクションには順番があるものと、順番を考えないものがあります
  • コレクションには項目の重複を許すものと許さないものがあります
  • Kotlin はリスト、セット、マップといったコレクションをサポートしています
  • Kotlin はコレクションを生成したり変換したりするための関数をあらかじめ多数用意しています(forEach, map, filter, sorted など)