【Swift】配列の配列について詳しく。

#この記事について

配列の配列で出来ることや、配列の配列の作り方についてまとめてみました。

- flatten
- joinWithSeparator
- split
- flatMap（追記）

の4つについて紹介します。

# flatten

```swift

extension SequenceType where Generator.Element : SequenceType {
    /// A concatenation of the elements of `self`.
    @warn_unused_result
    public func flatten() -> FlattenSequence<Self>
}
```
で定義されています。

簡単に言うと、配列の配列をすべて統合して、1つの配列にしてくれます。

## 使い方

`flatten`したままだと、`FlattenBidirectionalCollection`という仰々しい型のままなのですが、`map`や`[T]( )`を使うと望みの型が得られます。
そのままfor文で回す際はそういった処理は不要です。

```swift

let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

arrayOfArray.flatten()
// FlattenBidirectionalCollection<Array<Array<Int>>>(_base: [[1, 2, 3], [4, 5, 6], [7, 8, 9]])

arrayOfArray.flatten().map { $0 }
[Int](arrayOfArray.flatten())
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```


# joinWithSeparator

##その1

```swift

extension SequenceType where Generator.Element : SequenceType {
    /// Returns a view, whose elements are the result of interposing a given
    /// `separator` between the elements of the sequence `self`.
    ///
    /// For example,
    /// `[[1, 2, 3], [4, 5, 6], [7, 8, 9]].joinWithSeparator([-1, -2])`
    /// yields `[1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]`.
    @warn_unused_result
    public func joinWithSeparator<Separator : SequenceType where Separator.Generator.Element == Generator.Element.Generator.Element>(separator: Separator) -> JoinSequence<Self>
}

```
で定義されています。

###使い方

例にあるように、配列と配列の間に`Separator`を挿入します。
注意するべきところは、`Separator`も`SequenceType`、つまり、配列であるというところです。

```swift

let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

arrayOfArray.joinWithSeparator([-1, -2])
// JoinSequence<Array<Array<Int>>>(_base: [[1, 2, 3], [4, 5, 6], [7, 8, 9]], _separator: ContiguousArray([-1, -2]))

arrayOfArray.joinWithSeparator([-1, -2]).map { $0 }
[Int](arrayOfArray.joinWithSeparator([-1, -2]))
// [1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]
```

こちらも`map`や`[T]( )`で整形できます。

##その2

```swift

extension SequenceType where Generator.Element == String {
    /// Interpose the `separator` between elements of `self`, then concatenate
    /// the result.  For example:
    ///
    ///     ["foo", "bar", "baz"].joinWithSeparator("-|-") // "foo-|-bar-|-baz"
    @warn_unused_result
    public func joinWithSeparator(separator: String) -> String
}

```

で定義されています。

つまり、`[String]`型の配列だと、`separator`で配列内の要素を結合させた`String`を返してくれます。

###使い方

```swift

let strArray = ["foo", "bar", "buz"]

strArray.joinWithSeparator("-|-")
// "foo-|-bar-|-buz"
```

---

Pythonの`join`のように使いたければ、

```swift

extension String {
    func join (seq: [String]) -> String {
        return seq.joinWithSeparator(self)
    }
}
```
と宣言して、

```swift

let strArray = ["foo", "bar", "buz"]

"".join(strArray)
// "foobarbuz"
```

のようにすることもできます。

#split

5種類ほどの定義があります。例として`CollectionType`の2つだけ。あとの3つは`SequenceType`

```swift

extension CollectionType where Generator.Element : Equatable {
    /// Returns the maximal `SubSequence`s of `self`, in order, around a
    /// `separator` element.
    ///
    /// - Parameter maxSplit: The maximum number of `SubSequence`s to
    ///   return, minus 1.
    ///   If `maxSplit + 1` `SubSequence`s are returned, the last one is
    ///   a suffix of `self` containing the remaining elements.
    ///   The default value is `Int.max`.
    ///
    /// - Parameter allowEmptySubsequences: If `true`, an empty `SubSequence`
    ///   is produced in the result for each pair of consecutive elements
    ///   satisfying `isSeparator`.
    ///   The default value is `false`.
    ///
    /// - Requires: `maxSplit >= 0`
    @warn_unused_result
    public func split(separator: Self.Generator.Element, maxSplit: Int = default, allowEmptySlices: Bool = default) -> [Self.SubSequence]
}

extension CollectionType {
    @warn_unused_result
    public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, @noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
}
```

- maxSplit: 最大分割数（デフォルトは`Int.max`）
- separator: 配列の切れ目を指定する
- allowEmptySlices: 空の配列の生成も許容する（デフォルトは`false`）

##使い方

```swift

let array = [7, 2, 1, 2, 1, 1, 3, 2, 3, 4, 1, 5]

array.split(1)
// [ArraySlice([7, 2]), ArraySlice([2]), ArraySlice([3, 2, 3, 4]), ArraySlice([5])]

array.split(1).map { $0.map { $0 } }
array.split(1).map { [Int]($0) }
// [[7, 2], [2], [3, 2, 3, 4], [5]]
```

```swift

// *** allowEmptySlices: true

array.split(1, allowEmptySlices: true)
// [ArraySlice([7, 2]), ArraySlice([2]), ArraySlice([]), ArraySlice([3, 2, 3, 4]), ArraySlice([5])]

array.split(1, allowEmptySlices: true).map { $0.map { $0 } }
array.split(1, allowEmptySlices: true).map { [Int]($0) }
// [[7, 2], [2], [], [3, 2, 3, 4], [5]]
```
```swift

// *** isSeparatorで指定（偶数部分で分割）

array.split { $0 % 2 == 0 }
// [ArraySlice([7]), ArraySlice([1]), ArraySlice([1, 1, 3]), ArraySlice([3]), ArraySlice([1, 5])]

array.split { $0 % 2 == 0 }.map { $0.map { $0 } }
array.split { $0 % 2 == 0 }.map { [Int]($0) }
// [[7], [1], [1, 1, 3], [3], [1, 5]]
```
# 上記の組み合わせで出来ること

## 配列内のある要素を削除した配列を生成する

```swift

let array = [7, 2, 1, 2, 1, 1, 3, 2, 3, 4, 1, 5]

// -- 1を削除 -- array.filter { $0 != 1 }

array.split(1).flatten().map { $0 }
[Int](array.split(1).flatten())
// [7, 2, 2, 3, 2, 3, 4, 5]

// -- 偶数を削除 -- array.filter { $0 % 2 != 0 }

array.split { $0 % 2 == 0 }.flatten().map { $0 }
[Int](array.split { $0 % 2 == 0 }.flatten())
// [7, 1, 1, 1, 3, 3, 1, 5]
```

## 配列内のある要素を別の値と置換する

```swift

let array = [7, 2, 1, 2, 1, 1, 3, 2, 3, 4, 1, 5]

// -- 1を0に -- array.map { $0 == 1 ? 0 : $0 }

array.split(1, allowEmptySlices: true).joinWithSeparator([0])
// JoinSequence<Array<ArraySlice<Int>>>(_base: [ArraySlice([7, 2]), ArraySlice([2]), ArraySlice([]), ArraySlice([3, 2, 3, 4]), ArraySlice([5])], _separator: ContiguousArray([0]))

array.split(1, allowEmptySlices: true).joinWithSeparator([0]).map { $0 }
[Int](array.split(1, allowEmptySlices: true).joinWithSeparator([0]))
// [7, 2, 0, 2, 0, 0, 3, 2, 3, 4, 0, 5]
```

#追記

@koher さんのご指摘により、`[T]`型への変換がとても簡単にできるようになりました。
ありがとうございます。

[Swift 2.0の新しいflatMapが便利過ぎる](http://qiita.com/koher/items/6a95cb8edb04fb81f787)にあるような、`nil`の扱い以外にも`flatMap`は便利過ぎでした。

#flatMap

##その1 - `nil`の扱いの`flatMap`

```swift

extension SequenceType {
    /// Return an `Array` containing the non-nil results of mapping
    /// `transform` over `self`.
    ///
    /// - Complexity: O(*M* + *N*), where *M* is the length of `self`
    ///   and *N* is the length of the result.
    @warn_unused_result
    public func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]
}
```

##その2 - 配列の配列に対しての`flatMap`

```swift

extension SequenceType {
    /// Return an `Array` containing the concatenated results of mapping
    /// `transform` over `self`.
    ///
    ///     s.flatMap(transform)
    ///
    /// is equivalent to
    ///
    ///     Array(s.map(transform).flatten())
    ///
    /// - Complexity: O(*M* + *N*), where *M* is the length of `self`
    ///   and *N* is the length of the result.
    @warn_unused_result
    public func flatMap<S : SequenceType>(transform: (Self.Generator.Element) throws -> S) rethrows -> [S.Generator.Element]
}
```

###使い方

```swift

// 結合
let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
arrayOfArray.flatMap { $0 }
// [1, 2, 3, 4, 5, 6, 7, 8, 9]


// 1の削除
let array = [7, 2, 1, 2, 1, 1, 3, 2, 3, 4, 1, 5]
array.split(1).flatMap { $0 }
// [7, 2, 2, 3, 2, 3, 4, 5]
```

今まで、

```swift

arrayOfArray.flatten().map { $0 }
[Int](arrayOfArray.flatten())

array.split(1).flatten().map { $0 }
[Int](array.split(1).flatten())
Array(array.split(1).map { $0 }.flatten())
```

としていたのを随分すっきりと書けるようになりました。