[Swift] first last second third

# **first**, **last** はともかくとして、**second**, **third** って、何じゃ？

#### タイトルを見て奇異に感じた方が多いと思います

至極単純な発想で、**配列**の先頭の要素を**first**で参照できるならば、二番目、三番目の要素を**second**, **third** で参照できたら、コードが読みやすいかな？ って。

今回は、そんな**配列**に関する内容です。

<i>**first**, **last** は **Computed property**（計算型プロパティ）ですが、ここでは単に **first**, **last**と呼び捨てにします。</i>

_また、分かりやすい説明にしたいため、厳密な型やプロトコルの定義に基づく解説とは、少し外れるところもありますが、ご容赦ください。_

# **first**, **last**の正体

**Swift**には、**Collection**（**Collection**プロトコルを継承した型）の代表として、**Array**, **Set**, **Dictionary**がありますが、**last**が在るのは、**Array**だけです。**first**はどれも持っていますが。

##### まず、**first**がどこで定義されているかというと、[**Collection**](https://developer.apple.com/documentation/swift/collection/)プロトコルです。

```swift:extension Collection
  public var first: Element? {
    let start = startIndex
    if start != endIndex { return self[start] }
    else { return nil }
  }
```

（_startIndex == endIndex とは、要素が一つも無い、空のコレクションの場合_）


**Collection**は同じ属性のオブジェクトを「ある規則」により塊（かたまり）として保持するデータ構造（プロトコル）です。「ある規則」の部分が、**Array**, **Set**, **Dictionary**の特徴そのものです。
**Array**, **Set**, **Dictionary**は、**Collection**プロトコルに準拠しているため、どれも**first**を持っています。

##### 次に、**last**がどこで定義されているか調べてみると、[**BidirectionalCollection**](https://developer.apple.com/documentation/swift/bidirectionalcollection/)プロトコルです。**Collection**にはありません。


```swift:extension BidirectionalCollection
  public var last: Element? {
    return isEmpty ? nil : self[index(before: endIndex)]
  }
```

（_こちらは isEmpty で空のコレクションを判定しています_）

**BidirectionalCollection**はその名の通り、先頭からと最後からの双方向からアクセスできるコレクションです。
**Array**は、さらに、添え字を使ってランダムにアクセスできますね。

一方、**Set**, **Dictionary**には、何番目といった『**順序**』の概念がありません[^2]。だから、**last**がないのです。
要素を管理する上で「先頭」は当然知っています。「最後」は要素を順にたどっていけば分かるでしょうが、計算量が問題です。**last**は$O(1)$が要件のため、$O(N)$とか$O(logN)$かかる**last**は認めないということでしょう。

[^2]: 最近は、順序付きの Set, Dictionary （OrderedSet, OrderedDictionary）や 要素の並び順を保証した Set, Dictionary （SortedSet, SortedDictionary）のライブラリが、[swift-collections](https://github.com/apple/swift-collections)として公開されています。  


**Set**, **Dictionary**には『**順序**』はありませんが、**順番**にアクセスすることはできますね。この場合の**順番**は、「一つづつ順に取り出せる」という意味の順番です。`for-in`でイテレートできるということです。これは、[**Sequense**](https://developer.apple.com/documentation/swift/sequence)プロトコルに準拠しているからです。

_なお、ここで取り出される要素の順序は、要素を追加した順序とは無関係であることを、付け加えておきます。_

プロトコルの継承関係は↓こんなイメージです（イメージのため、本当の継承階層とは違います）。

```plantuml:'プロトコルの継承イメージ
@startuml
struct Array
struct Set
struct Dictionary
protocol BidirectionalCollection
protocol RandomAccessCellection
protocol Collection
protocol Sequence
Array <-- Collection
Array <-- RandomAccessCellection
Array <-- BidirectionalCollection
Set <-- Collection
'Set <-- Sequence
Dictionary <-- Collection
'Dictionary <-- Sequence
Collection <-- Sequence
@enduml
```

<br><br><br>前置きが長くなりましたが、本題に入ります。

# **second**, **third**を定義する

前述の通り、順序付けの概念が**Array**しかないため、**Array**の**extension**で定義しました。

```swift
extension Array {
    var second: Element? { self.count >= 2 ? self[1] : nil }
    var third: Element? { self.count >= 3 ? self[2] : nil }
}
```

見てのとおり、至ってシンプルです。

配列の先頭と二番目の要素を比較したいときは、
`if array.first! > array.second! { ・・・ }` みたいに使います。

**third**はおまけで、以降、**ten**ぐらいまで用意してもいいですが、それほど使い道は無いかな？と思います。


## 想定した使い方

**Swift**のタプルが**Hashable**では無いため、タプルを**Set**の要素や**Dictionary**の**key**にすることができません。そんなとき、タプル内の要素が同じ型の場合[^1]は、**Array**で代替しています。
その場合、タプルの場合だと`tuple.0, tuple.1`アクセスしますが、配列で代用したときは、`array.first, array.second`でアクセスします（<b>C++</b>の<b>pair</b>型を真似た）。

必ず要素が存在していることが分かっている（場合に使用する）ので、オプショナル型をやめて単純にします。

```swift
extension Array {
    var first: Element { self[0] }
    var second: Element { self[1] }
    var third: Element { self[2] }
    var last: Element { self[self.count - 1]  }
}
```


[^1]: _タプル内の要素の型が異なる場合は、専用の構造体（class/struct）を定義して**Hashable**に準拠する必要があります。_


# 最後から二番目

**last**は最終要素ですが、最後から二番目（n番目）の要素をアクセスしたい場合もありますね。
そんな時のために、以下の**extension**も便利です。

```swift
extension Array {
    subscript(last last: Int) -> Element {
        get {
            //precondition(self.indices.contains(last), "out of bounds")
            return self[self.endIndex - last - 1]
        }
        set {
            //precondition(self.indices.contains(last), "out of bounds")
            self[self.endIndex - last - 1] = newValue
        }
    }
}
```

最終の要素は`array[last: 0]`、最後から二番目は`array[last: 1]`で、
`array[last: array.count - 1]`は先頭の要素です。

<img width="450" alt="IMG_0041.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/e7b682eb-b2ce-28c7-6638-0e6e33f4d02c.jpeg" />


（後ろからの添え字も0〜としたため、`python`のマイナス添え字とは異なります）


使う頻度は少ないですが、有ると便利です。

<br><br><br>もう一つ、おまけ

# 循環バッファのアクセス

下記の**subscript**は、循環バッファのように、添え字が要素数を超えたら、先頭に移ってアクセスができるものです。逆に添え字がマイナスになると、今度は要素の最終に移ります。これは、`python`のマイナス添え字に似た考えです。

```swift
extension Array {
    subscript(ring ring: Int) -> Element {
        get { self[((ring % self.count) + self.count) % self.count] }
        set { self[((ring % self.count) + self.count) % self.count] = newValue }
    }
}
```

以下の実行例をみていただくと、ちゃんと循環していることが分かると思います。

<img width="450" alt="IMG_0040.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/03c84bc9-ff79-7e4f-4c2e-8a14331ed303.png" />





**以上**です。何かの参考になれば嬉しいです。