[Swift5]日付でソートした配列の順序変更を、その他の配列にも適用させる


# はじめに
一つの配列を日付順でソートして他の配列にもその順序を適用させる方法のご紹介です。
# 前提
処理したい配列が以下のような複数の一次元配列の場合で
「入会日」の配列を日付順にソートし、
さらに名前、年齢の配列にもその順序変更を適用させたい場合とします。

```swift
//入会日
let date: [String] = ["2019年10月01日", "2019年09月02日", "2018年11月01日"]
//名前
let name: [String] = ["山田", "田中", "佐藤"]
//年齢
let age: [Int] = [24, 35, 46]
```

### 課題
- 日付のソートの方法
- 日付のソートの順序を他の配列にも適用させる方法

## 日付をDate型に変換してソート
まずは配列dateをDate型に変換してソートします

```swift
var newDateArray = [Date]()
for date in dateArray {
    let formatter = DateFormatter()
    formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM", options: 0, locale: Locale(identifier: "ja_JP"))
    let formattedDate = formatter.date(from: date)
    print(formattedDate!)
    newDateArray.append(formattedDate!)
}
print(newDateArray)
//[2018-10-31 15:00:00 +0000, 2019-09-01 15:00:00 +0000, 2019-09-30 15:00:00 +0000]
```

### 気になった点
- 日付のみのデータを上の方法でフォーマットすると
2019年10月01日　が　2019-09-30 15:00:00 +0000　と
1日前の日付になってしまいますが順序変更のindexを取得するだけなので問題ないです。

## 【不採用】日付はString型のままソート

```swift
let joinDate: [String] = ["2019年10月01日", "2019年09月02日", "2018年11月01日", "2017年12月22日", "2018年12月01日"]
var sortedJoinDate = [String]()
sortedJoinDate = joinDate.sorted { $0 < $1 }
print(sortedJoinDate)
//["2017年12月22日", "2018年11月01日", "2018年12月01日", "2019年09月02日", "2019年10月01日"]
```
ちゃんとソートできているように見え、採用しかけたのですが、
今回は01日と 0付きなのでString型のままソートできますが、0抜き日付だとできません。
よって今回はこのやり方は不採用としました。

### 他の配列に順序変更を適用させる方法
- これはenumerated関数をうまく使うと解決できそうです。

# 完成したコード(enumerated関数を使ってoffsetを基準に並び替える)

```swift
let date: [String] = ["2019年10月1日", "2019年12月24日", "2018年11月1日"]
let name: [String] = ["山田", "田中", "佐藤"]
let age: [Int] = [24, 35, 46]

var dateArray = [String]()
var nameArray: [String] = [String]()
var ageArray: [Int] = [Int]()
var formattedDateArray = [Date]()
for date in date {
    let formatter = DateFormatter()
    formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM", options: 0, locale: Locale(identifier: "ja_JP"))
    let formattedDate = formatter.date(from: date)
    formattedDateArray.append(formattedDate!)
}

let dateSorted = formattedDateArray.enumerated().sorted { $0.element < $1.element }
print(dateSorted)
//[(offset: 2, element: 2018-10-31 15:00:00 +0000), (offset: 0, element: 2019-09-30 15:00:00 +0000), (offset: 1, element: 2019-12-23 15:00:00 +0000)]

for indexPathRow in 0..<formattedDateArray.count {
    //並べ替えた後のタプルからindex番号(offset)を取り出す
    let originalIndex = dateSorted[indexPathRow]
    dateArray.append(date[originalIndex.offset])
    nameArray.append(name[originalIndex.offset])
    ageArray.append(age[originalIndex.offset])
}
```
### 解説
- enumerated関数を適用させることで要素がタプルに変換されると同時に、offsetが順番に割り振られています。

```swift
[(offset: 2, element: 2018-10-31 15:00:00 +0000), (offset: 0, element: 2019-09-30 15:00:00 +0000), (offset: 1, element: 2019-12-23 15:00:00 +0000)]
```

- for構文で配列をループさせながらoriginalIndex.offsetでIndex番号を取得してformattedDateArrayの配列の順番で各配列の要素を取得しながら配列を再構成しています。

## 処理後のprint結果
```swift
print(dateArray)//["2018年11月1日", "2019年10月1日", "2019年12月24日"]
print(nameArray)//["佐藤", "山田", "田中"]
print(ageArray)//[46, 24, 35]
```
- UserDefaultsから引っ張ってきた配列を処理してUITableViewに表示する時など、応用が効きそうです。もっといい方法を思いついたら記事を更新したいと思います。

### 最後に

Swift学習１ヶ月半で、初のオリジナルアプリを作成中に調べた内容を記載しています。
より効率の良い書き方があったらご指摘のほどお願いいたします。
この記事が、他のプログラミング初学者のお役に立てば幸いです。