Swift で一次元配列を評価して二次元配列を生成する方法（自作高階関数）

以前 [Swiftで一次元配列を評価して二次元配列を生成する方法](http://qiita.com/shunsukekyuwa/items/f5be75940d1c5aba531d)という記事を読みましたが、その時は既存の `reduce` 関数でどうにかしようと考えました。

ところで今日 [Advanced Swift](https://www.objc.io/books/advanced-swift/) という本を読んで、**`map` はこんな風に作られているよ**というような記述を見かけて、「そう言えば確かによくよく考えればこれグルーピングであってリデュースではないよな」って思って、**じゃあ標準ライブラリーになければ自分でこれ作ればいいんじゃね？**って思いました。

アプローチは非常に簡単で、配列を全部走査して、隣り合う要素を何らかの方法で同じグループに所属するかどうかを判断し、すれば同じグループにまとめるし、しなければ新しいグループ作ればいいです。

というわけで早速作ってみました：

```swift:Array.swift
extension Array {
	
	private var lastIndex: Index {
		return self.index(before: self.endIndex)
	}
	
	private var lastElement: Element {
		get {
			return self[lastIndex]
		}
		set {
			self[lastIndex] = newValue
		}
	}
	
	public func group(condition: (_ previous: Element, _ next: Element) throws -> Bool) rethrows -> [[Element]] {
		
		guard let first = self.first else {
			return [[]]
		}
		
		var groupedArray: [[Element]] = [[first]]
		
		for next in self.dropFirst() {
			let previous = groupedArray.lastElement.lastElement
			
			if try condition(previous, next) == true {
				groupedArray.lastElement.append(next)
				
			} else {
				groupedArray.append([next])
			}
			
		}
		
		return groupedArray
		
	}
	
}
```

通常の `last` 要素は `Element?` で返されるし `get-only` なので、ここでかなりの頻度で最後の要素を操作するから、`private` な `get set` の `lastElement: Element` 変数を作りました。

そして配列に必ず最低でも 1 要素があることを保証し、そうでなければ空二次元配列を返します。
1 要素以上あれば、仮の `groupedArray: [[Element]]` を作ってとりあえずまず 1 個目の要素をぶちこんでおき、そして元配列の 2 番目以降の要素を走査しながら `groupedArray` の最後の要素と比較し、同じグループであれば最後のグループにこの要素を追加し、そうでなければ新しいブループを作って追加します、いたって単純。
同じグループであるかどうかの判断はここではせず、高階関数として `condition` を利用時に中身を定義してもらいます。

これで利用するときはグルーピングのルールを教えればグループされた二次元配列が作られます。

例えば、素数の数列を渡して、その中に十の桁が一致する数字をまとめたい、といった感じですと、

```swift
let primeNumbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
let groupedPrimeNumbers = primeNumbers.group { $0 / 10 == $1 / 10 }
print(groupedPrimeNumbers) //[[2, 3, 5, 7], [11, 13, 17, 19], [23, 29], [31, 37], [41, 43, 47]]
```

と、見事に 10 未満、10 以上で 20 未満、20 以上で 30 未満…といった感じにグルーピングしてくれました。めでたしめでたし。

============================追伸============================

せっかくなので `Array` だけでなくすべての `Sequence` に対応させてみました。

```Swift:Collection.swift
extension Collection {
	
	public var lastIndex: Index {
		guard let lastIndex = self.index(self.endIndex, offsetBy: -1, limitedBy: self.startIndex) else {
			fatalError("Index out of range")
		}
		return lastIndex
	}
	
}

extension Collection {
	
	public var lastElement: Iterator.Element {
		get {
			return self[lastIndex]
		}
	}
	
}
```

```swift:MutableCollection.swift
extension MutableCollection {
	
	public var lastElement: Iterator.Element {
		get {
			return self[lastIndex]
		}
		set {
			self[lastIndex] = newValue
		}
	}
	
}
```

```swift:Sequence.swift
extension Sequence {
	
	public func group(condition: (_ previous: Iterator.Element, _ next: Iterator.Element) throws -> Bool) rethrows -> [[Iterator.Element]] {
		
		var iterator = self.makeIterator()
		guard let first = iterator.next() else {
			return [[]]
		}
		
		var groupedArray: [[Iterator.Element]] = [[first]]
		
		while let next = iterator.next() {
			let previous = groupedArray.lastElement.lastElement
			
			if try condition(previous, next) == true {
				groupedArray.lastElement.append(next)
				
			} else {
				groupedArray.append([next])
			}
			
		}
		
		return groupedArray
		
	}
	
}
```

`lastIndex` とか `lastElement` とかについて特に何も説明する必要ないと思いますが、`group` の実現のところで、前 `Array` で実現した際に使った `for` 文がなくなって、代わりに `while let next = iterator.next()` になりました。これは `Sequence` プロトコルの `Iterator` というもので、簡単に言うと中身を順番に取ってきてくれるやつです。詳しくは[公式資料](https://developer.apple.com/reference/swift/sequence)を参照すれば分かるかと。これで `Array` だけでなく、すべての `Sequence` 対応の型をグルーピングできるようになります。

~~ただぶっちゃけ `MutableCollection` の存在意義がわからない。`set` は `mutating` なのでそれだけで判別できるから、なんで `get-only` の `Collection` と `get set` の `MutableCollection` があるのか。これじゃあまるで `NSArray` と `NSMutableArray` と変わらないじゃないか…~~と思ったがよくよく考えてみたら `MutableCollection` がなかったらコレクションの中身だけを変えるかそれともコレクション丸ごと変えるかを判別できないな確かに