Swift The Programming Language Collection Types & Control Flow まとめ


# Collection Types
+ Array: 順序を持つ値のcollection
+ Set: 順序を持たないuniqueな値のcollection
+ Dictionary: 順序を持たないkeyとvalueの関連のcollection

# Mutability of Collections(コレクションの可変性)
+ コレクションを生成して変数に代入した場合、生成されるコレクションは可変
+ コレクションを生成後にアイテムを追加、削除、変更してコレクションを変更することができる

# Arrays
## Array Type Shorthand Syntax
+ SwiftでのArrayのtypeは、`Element`がArrayに格納できる値のtypeとしたとき、`Array<Element>`と記述する
+ `[Element]`と簡略して書くこともできる
+ 後者の方が望ましい

## Creating an Empty Array
```
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// "someInts is of type [Int] with 0 items." と出力
```

```
someInts.append(3)
// someInts には Int 型の値が 1 件
someInts = []
// someInts は空配列になったが、型は [Int] のまま
```

## Creating an Array with a Default Value
```
var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
// threeDoubles は [Double] 型で、[0.0, 0.0, 0.0]
```

## Creating an Array by Adding Two Arrays Together
+ `+`でcompatible(一致する)typeの配列を足しあわせて新たな配列を生成できる
+ 新たな配列のtypeは足しあわせたarrayのtypeから推論

```
var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5)
// anotherThreeDoubles は [Double] 型で、[2.5, 2.5, 2.5]

var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is [Double] と推論され、[0.0, 0.0, 0.0, 2.5, 2.5, 2.5
```

## Creating an Array with an Array Literal
```
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList を 2つの初期値で初期化


var shoppingList = ["Eggs", "Milk"]
// type推論によりこのように宣言できる
```

## Accessing and Modifying an Array
+ `count`プロパティで配列内の要素の数は確認できる
+ `isEmpty`プロパティを利用すれば`count`プロパティが0かを確認できる
+ `append`メソッドを呼び出してarrayの末尾に新しい要素を追加することができる
+ `+=`でarrayが持つ1つ以上の要素を追加できる
```
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
```
+ 取得したいvalueのindex(subscript syntax)を利用してvalueを取得できる
+ subscript syntaxを利用して、指定したindexのvalueを変更できる
+ 値の範囲を一度に変更するためにsubscript syntaxを利用することができる
```
shoppingList[4...6] = ["Bananas", "Apples"]
```
+ `insert(_:)メソッドを用いて、Arrayの指定したindexにvalueをinsertできる
```
shoppingList.insert("Maple Syrup", atIndex: 0)
```
+ `removeAtIndex(_:)`メソッドで同様にvalueを削除できる

注意:
+ Arrayの末尾に新しい要素を追加するのにsubscript syntaxhは使えない
+ Arrayの範囲外となるindex valueにアクセス、または変更を試みた場合、実行時エラーが起きる

+ `removeLast()`メソッドでArrayの末尾の値を、引数なしで削除できる

## Iterating Over an Array(繰り返し処理）
+ `for-in`ループで繰り返し処理できる
+ index valueが必要なときは、`enumerate()`メソッドを使う。`enumerate()`メソッドはArray内の各要素をindexとvalueで構成されるtupleでreturnする

```
for (index, value) in shoppingList.enumerate() {
    print("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
```

# Sets
## Hash Values for Set Types
+ Setに格納するためには`hashable`であることが必要
+ hash valueは、例えば`a == b`の実行結果が`a.hashValue == b.hashValue` と同じになるように、すべてのオブジェクトを平等に比較するためにInt value

## Set Type Syntax
+ `Set<Element>`と記述。簡略な方法はない

## Creating and Initializing an Empty Set
```
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// "letters is of type Set<Character> with 0 items." と出力

letters.insert("a")
// letters には Character 型の値が 1 件
letters = []
// letters は空集合になったが、型は Set<Character> のまま
```

## Creating a Set with an Array Literal
+ SetをArrayリテラルから推論することはできないため、type`Set`は明示的に宣言する必要がある
 
```
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres を 3 件の初期値で初期化

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 要素のtypeは宣言しなくてもok
```

## Accessing and Modifying a Set
+ `count`,`isEmpty`, `insert(_:)`, `remove(_:)`, `removeAll()`, `contains(_:)`などメソッドある

## Iterating Over a Set
+ `for-in`ループで繰り返し処理できる
+ `Set`typeは順序を持たないので集合内のvalueを特定の順に繰り返し処理したいときは`sort()`メソッドを使用する

```
for genre in favoriteGenres.sort() {
    print("\(genre)")
}
// Classical
// Hip hop
// Jazz
```

## Performing Set Operations
+ `intersect(_:)`: 共通要素
+ `exclusiveOr(_:)`: どちらかしかにない要素
+ `union(_:)`: 和集合
+ `subtract(_:)`: 取り除く

## Set Membership and Equality
包含関係を示す(部分集合か真部分集合か）メソッドがある

# Dictionaries
+ 辞書は順番を持たないcollection
+ 各valueはuniqueなkeyで関連付けられ辞書内でのvalueのidとなる

## Dictionary Type Shorthand Syntax
+ `Dictionary<Key, Value>`と記述。
+ 簡略化すると`[Key: Value]` Dictionaryは型推論コストが高いので簡略に書きたい。

## Creating an Empty Dictionary
```
var namesOfIntegers = [Int: String]()

namesOfIntegers = [:]
// namesOfIntegers は再び [Int: String] 型の空辞書
```

## Creating a Dictionary with a Dictionary Literal
```こんな感じ
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 同じtypeのKeyとvalueを持つDictionary Literalで初期化する場合はtypeを記述する必要ない
```

## Accessing and Modifying a Dictionary
+ 基本配列と同様
+ 特定のkeyに関連するvalueを変更するためにはsubsctript syntaxを利用する

```
airports["LHR"] = "London Heathrow"
// "LHR" の値は "London Heathrow" に変更されている
```
+ accessするときはkeyに関連するvalueがない可能性もあるのでoptional valueがreturnする
+ Dictionaryからkeyとvalueのpairを削除したいときはkeyに`nil`を代入すれば良い
+ もしくは`removeValueForKey(_:) `で削除

## Iterating Over a Dictionary
+ Dictionary内のkeyとvalueのペアをfor-inループで繰り返し処理可能
+ 辞書の各項目はarrayと同様にtupleでreturnされる
+ `.keys`でkeyを繰り返し処理するためのcollectionを取得できる
+ `.values`でvalueを繰り返し処理するためのcollectionを取得できる

```
let airportCodes = [String](airports.keys)
// airportCodes は ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames は ["Toronto Pearson", "London Heathrow"]
```

# Control Flow
## For-In Loops
+ シーケンスの各値が必要ない場合は`_`でおk

## While Loops
```
while condition {  // 条件がtrueなら繰り返す
    statements
}
```

### Repeat-While
```
repeat {
    statements
} while condition // 条件がfalseになるまで繰り返す
```

## Conditional Statements
### If
```
if conditions1 {
  hogehoge
} else if conditions2 {
  fugafuga
} else {
  hahahaha
}
```

## Switch
```
switch some value to consider {
case value 1:
    respond to value 1
case value 2,
value 3:
    respond to value 2 or 3
default:
    otherwise, do something else
}
```
+ 最初に一致したswitch caseを完了後すぐにswitch文全体の実行は終了される(breakなしで)
+ 各caseの本体には、少なくとも一つの実行文が必要
+ 全てのcaseを網羅していたら`default:`は必要ない。defaultはない方が望ましい

### Value Bindings
```
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}
// "on the x-axis with an x value of 2" と出力
```

### Where
```
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// "(1, -1) is on the line x == -y" と出力
```

## Control Transfer Statements(条件転送文)
### Continue
+ 実行中のループを停止して、次の周回の初めから再開します。
+ ループを出てしまうのではなく、現在の周回を完了したということです。

### Break
#### Break in a Loop Statement
+ ループの実行を即座に終了し、ループの閉じ括弧 (}) の直後のコードに制御を転送します。

#### Break in a Switch Statement
+ switch 文の実行を即座に終了し、switch 文の閉じ括弧 (}) の直後のコードに制御を転送します。

## Fallthrough 
+ caseの処理が終わったらdefault caseの処理をする

```
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// "The number 5 is a prime number, and also an integer." と出力
```

## Labeled Statements
+ ループ文または条件文にラベルを付けることができる
+ 複数ネストされたループがある場合、continue 文が影響するループを明確にできるようにするため

```
gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // 最後のマスに移動し、ゲーム終了
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        // 最後のマスを越えたため、サイコロを振り直す
        continue gameLoop
    default:
        // マスを移動し、上下移動を適用
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")
```

## Early Exit
+ guard 文は、if文と同様に、式のBool値によってコードを実行する。
+ guard 文の後のコードが実行されるには、guard 文の条件が true である必要があります。
+ if 文と異なり、guard 文には「常に」else 節があり、条件がtrueでない場合にelse節内のコードが実行されます。

### メリット
+ guard 文を使用することは、同じチェックをif文で実施することと比較して、コードの可読性が向上する
+ 実行するコードをelseブロックで囲って記述する必要がなく、条件に反した場合の処理コードを条件のすぐ後に記述することができる

## Checking API Availability
+ API の可用性チェックをビルトインでサポートしており、デプロイ対象で利用できない API を誤って利用してしまうことがないようにできる
+ Swift は、利用不可能なAPIを利用しようとした場合、コンパイル時にエラーを報告する

```
if #available(iOS 9, OSX 10.10, *) {
    // iOS の iOS 9 API を使用、および OS X の OS X v10.10 API を利用
} else {
    // それより前の iOS および OS X の API にフォールバック
}
```

```
if #available(platform name version, ..., *) {
    statements to execute if the APIs are available
} else {
    fallback statements to execute if the APIs are unavailable
}
```