Lesson 2.5 Collections
これまでのところ、このコースでは、定数でも変数でも、単一の項目を扱うことを学びました。しかし、オブジェクトのグループ全体を操作する方が理にかなっていると感じることがあります。コレクションを使用すると、一度に複数のオブジェクトを参照できます。たとえば、12個の別々の定数を管理する代わりに、1つの定数を使用して1ダースの卵を扱うことができます。このレッスンでは、Swiftで利用可能なさまざまなコレクションタイプと、プログラムに適したコレクションを選択する方法について学習します。
あなたが学ぶこと
・定数コレクションと変数コレクションを宣言する方法
・配列と辞書から値を追加および削除する方法
・適切なコレクションタイプの選び方
Vocabulary
array
dictionary
p.169
Swiftは、頻繁に作業する2つのコレクションタイプを定義します。配列と辞書です。各タイプは、複数のオブジェクトを操作するための独自のメソッドを提供します。さまざまなタイプの学習を進めるにつれて、アイテムの追加/削除、個々のアイテムへのアクセス、コレクション内のデータに関する型情報の提供など、特定の機能を共有していることに気付くでしょう。
アレイ
Swiftで最も一般的なコレクションタイプは、同じ型付けられた値の順序付きリストを格納する配列です。配列を宣言するときは、コレクションに保持される値のタイプを指定することも、型推論システムに型を検出させることもできます。
配列は、多くの場合、IntまたはStringリテラルに似たリテラルを使用して初期化されます。配列リテラルを宣言するには、値のコレクションを括弧で囲み、カンマで値を区切ります。
同様の構文を使用して、文字列を格納する配列を宣言します。次の例では、変数の型であるStringが括弧で囲まれていることに注意してください。
型推論は「Anne」、「Gary」、「Keith」が文字列であると判断できるため、配列の型を指定せずに実際にステップをスキップして配列を宣言することができます。
しかし、型推論がそれを発見することができるにもかかわらず、配列の型を指定したい状況があるかもしれません。たとえば、8ビット整数(-127から128までの数字)のコレクションが欲しいと想像してみてください。まず、次の数値のコレクションに変数を割り当てます。
p.170
Swiftは、すべての値をInt型に推測し、数値を整数の配列または[Int]に設定します。この推論は確かに正しいですが、問題があります。Intは-127から128の範囲を超える正と負の数を保持できます。Swiftが配列を小さな整数に制限することを理解できるように、値が前述の範囲に制限されている8ビット整数の配列である[Int8]として型を指定できます。
Var 数値: [Int8] = [1, -3, 50, 72, -95, 115]
[Int8]型の配列リテラルに300などの大きな数を含めようとした場合はどうなりますか?300がInt8の最大数より大きいため、Swiftはエラーを返します。推論型が十分に具体的でない場合は、型を指定する必要があり、許可したくない値を制限するのに役立ちます。
配列に特定の値が存在するかどうかを確認することはしばしば便利です。これを行うには、contains(_:)メソッドを使用して、目的の値を渡すことができます。配列に値が含まれている場合、式はtrueです。それ以外の場合はfalseです。
Let numbers = [4, 5, 6]
If numbers.contains(5) {
print("There is a 5")
}
このコースの早い段階で、定数は宣言されると変更できないことを学びました。Let: コレクション内のアイテムを追加、削除、または変更することはできません。ただし、varを使用してコレクションを変数内に格納すると、コレクション内のアイテムに追加、削除、または変更することができます。さらに、コレクションを空にしたり、変数を完全に別のコレクションに設定したりできます。
p.171
配列型
配列はバスケットのようなものです。空から始めて、後で値で埋めることができます。しかし、配列リテラルに値が含まれていない場合、その型はどのように推測できますか?
型注釈、コレクション型注釈、または配列初期化子を使用して、配列の型を宣言できます。
この例では、従来の型注釈を持つ配列を定義しています。
Var myArray: [Int] = []
この例では、特別なコレクション型アノテーションを使用して配列を定義しています。これは、作業中のコードで遭遇した場合に備えて、あまり一般的ではない慣行です。
Var myArray: Array<Int> = []
型名の後に()を追加することですべてのオブジェクトを初期化できるのと同様に、[Int]の後に()を追加して、Intオブジェクトの空の配列を初期化できます。また、将来このコードに遭遇した場合に備えて、このコードにも精通している必要があります。
Var myArray = [Int]()
配列の操作
配列リテラルを使用するのが面倒な状況やエラーが発生しやすい状況が見つかる場合があります。たとえば、配列を100個のゼロで埋めたいとします。配列リテラル形式では、100個のゼロをすべて入力する必要があり、それらを誤って数えるのは簡単です。
大丈夫です。Swiftには解決策があります。100個のゼロを数える代わりに、次の初期化子を使用して、デフォルト値を繰り返してカウント100の配列を作成できます。
Var myArray = [Int](繰り返し: 0, count: 100)
p.172
配列内のアイテムの数を調べるには、そのcountプロパティを使用できます。配列が空かどうかを確認したい場合はどうなりますか?カウントを0と比較するのではなく、ブール値を返す配列の isEmpty プロパティを確認できます。
Let count = myArray.count
myArray.isEmpty { }の場合
配列を定義したら、さまざまなメソッドとプロパティを使用して配列にアクセスしたり変更したりできます。配列の下付き文字構文を使用することもできます。これは、文字列の下付き文字構文と同じです。コレクションから特定の値を取得するには、アクセスする値のインデックスを指定します。配列の値は常にゼロインデックス付きです。つまり、配列の最初の要素のインデックスはゼロです。次の例では、ファーストネームのコレクションの最初の値を取得します。
Let firstName = names[0]
下付き文字構文を使用して、特定のインデックスの値を変更することもできます。=記号の左側に下付き文字を置くことで、現在の値にアクセスするのではなく、特定の値を設定できます。以下の例では、コレクションの2番目の名前を「ポール」に変更しています。
Names[1] = "ポール"
配列を定義し、いくつかの値を設定した後、多くの場合、新しい値を追加する必要があります。変数配列の追加関数を使用して、配列の最後に新しい要素を追加できます。複数の要素を一度に追加するには、+=演算子を使用します。
Var names = ["エイミー"]
Names.append("ジョー")
名前 += ["キース", "ジェーン"]
Print(names) //["エイミー", "ジョー", "キース", "ジェーン"]
p.173
配列の末尾に新しい要素を表示させたくなかった場合はどうなりますか?変数配列には、値とインデックスを指定できるinsert(_: at:)関数もあります。このシナリオでは、前の例のように、有効なインデックスを指定する必要があります。
配列はゼロインデックスであるため、最初の要素のインデックスは常に0で、最後の要素のインデックスはcount-1に等しい。次の例では、配列の先頭に「ボブ」が挿入されます。
Names.insert("ボブ", at: 0)
同様に、remove(at:)関数は、指定されたインデックスのアイテムを削除するために機能します。Insert(_: at:)とは異なり、値を入力する必要はありません。この関数は、以下の例のように、デフォルトで削除されたアイテムを返します。もう1つのメソッドはremoveLast()で、配列から最後の項目を削除し、インデックスを計算する必要がなくなります。最後に、removeAll()メソッドは配列からすべての要素を削除します。
Swiftでは、同じタイプの既存の配列を2つ追加することで、新しい配列を作成することもできます。結果の配列内で最初に来る配列を指定できます。
Var myNewArray = firstArray + secondArray
配列内の配列はどうですか?配列リテラル構文を使用して、より大きな配列の中に2つの小さな配列を含めます。その後、コンテナ配列の下付き文字構文を使用して、ネストされた配列の1つにアクセスできます。ネストされた配列の1つ内の特定の要素にアクセスするには、2組の下付き文字を使用できます。
Let array1 = [1,2,3]
p.174
Let array2 = [4,5,6]
Let containerArray = [array1, array2] //[ [1,2,3], [4,5,6] ]
Let firstArray = containerArray[0] //[1,2,3]
Let firstElement = containerArray[0][0] //1
辞書
Swiftの2番目のタイプのコレクションは辞書です。Swift辞書は、単語のリストとその定義を含む現実世界の辞書のように、それぞれが関連する値を持つキーのリストです。辞書の各単語が一意であるのと同じように、各キーは一意でなければなりません。そして、英語の辞書が単語を簡単に検索できるようにアルファベット順であるように、Swift辞書はキー検索を非常に高速にするように最適化されています。
辞書リテラルを使用して辞書を設定できます。角括弧で囲まれたカンマ区切りのキーと値のペアのリストです。コロンは、各キーとその結果の値を区切ります。
[Key1:value1、key2:value2、key3:value3]
配列と同様に、辞書の型は辞書リテラルで使用される型に基づいて推測できます。ゲームにハイスコアのリストを保存したいとします。プレイヤーの名前をキーとして使用し、プレイヤーのスコアを対応する値として使用します。辞書の型は、[String: Int] または Dictionary<String, Int> のいずれかとして推測できます。
Varスコア = ["リチャード": 500, "ルーク": 400, "シェリル": 800]
他の2つのコレクションタイプと同様に、辞書にはキーと値のペアの数を決定するカウントプロパティがあり、辞書にキーと値のペアがない場合はisEmptyプロパティがtrueを返し、そうでない場合はfalseを返します。空の辞書を作成するための構文は、おそらく今では馴染みがあるように見えるでしょう。
Var myDictionary = [文字列: Int]()
p.175
Var myDictionary = 辞書<String, Int>()
Var myDictionary: [文字列: Int] = [:]
辞書の追加/削除/変更
下付き文字構文は辞書で特に便利です。Swift辞書の順序は重要ではないので、インデックスはなく、インデックスに関連付けられたサブスクリプトエラーのリスクもありません。
次の例では、ハイスコアの辞書に新しいスコアを追加します。キー「Oli」が辞書にすでに存在する場合、このコードは古い値を新しい値に置き換えます。
スコア["Oli"] = 399
しかし、辞書に置き換える前に辞書に古い値があるかどうかを知りたい場合はどうなりますか?updateValue(_:, forKey:) を使用して辞書を更新することができ、メソッドから返される値は、存在する場合、古い値に等しくなります。次の例では、oldValueは更新前のRichardの古い値に等しくなります。値がない場合、oldValueはnilになります。Nilキーワードについては後で詳しく学びます。これは、値がないことを表す特別な方法です。
Let oldValue = scores.updateValue(100, forKey: "リチャード")
Swiftは、メソッドから値が返された場合にのみコードを実行するために、 if-let構文を使用します。既存の値がない場合、括弧内のコードは実行されません。
If let oldValue = scores.updateValue(100, forKey: "リチャード") {
print("リチャードの古い値は\(oldValue)")
}
p.176
辞書から項目を削除するには、下付き文字構文を使用して値をnilに設定できます。値の更新と同様に、削除する前に古い値を返す必要がある場合、辞書にはremoveValue(forKey:)メソッドがあります。
Varスコア = ["リチャード": 100, "ルーク": 400, "シェリル": 800]
scores["Richard"] = nil //["Luke": 400, "Cheryl": 800]
If let oldValue = scores.removeValue(forKey: "Luke") {
print("ルークのスコアは、彼が停止する前に\(oldValue)でした
遊ぶ」)
}
辞書へのアクセス
Swift辞書は、他のコレクションタイプに含まれていない2つのプロパティを提供します。キーを使用して辞書内のすべてのキーのリストを返し、値を使用してすべての値のリストを返すことができます。これらのコレクションを後で使用する場合は、配列に変換する必要があります。
辞書の場合、結果はキーの対応する値になります。ただし、キーが辞書にない場合、括弧内のコードは実行されません。
If let myScore = scores["Luke"] {
印刷(myScore)
}
p.177
if let henrysScore = scores["Henry"] {
print(henrysScore) //not executed; "Henry" is not a key in
the dictionary
}
Console Output:
400