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

# この記事について

[【Swift】配列の配列について詳しく。 - Qiita](http://qiita.com/ken0nek/items/dce8281570a2dcf48e17)で「配列の配列」についてまとめたのですが、Swift3で変更点が多くあったので別記事にしました。

- `joined`
- `split`
- `flatMap`


# `joined`

`flatten`がなくなり`joined`になりました。

## 配列の要素が`String`のとき

```swift

extension Array where Element == String {

    /// Returns a new string by concatenating the elements of the sequence,
    /// adding the given separator between each element.
    ///
    /// The following example shows how an array of strings can be joined to a
    /// single, comma-separated string:
    ///
    ///     let cast = ["Vivien", "Marlon", "Kim", "Karl"]
    ///     let list = cast.joined(separator: ", ")
    ///     print(list)
    ///     // Prints "Vivien, Marlon, Kim, Karl"
    ///
    /// - Parameter separator: A string to insert between each of the elements
    ///   in this sequence. The default separator is an empty string.
    /// - Returns: A single, concatenated string.
    public func joined(separator: String = default) -> String
}
```

### 使い方

```swift
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let list = cast.joined(separator: ", ")
print(list)
// "Vivien, Marlon, Kim, Karl"
```

単に結合するだけのときは引数なしでOK

```swift
let aiu = ["あ", "い", "う"]
let list = aiu.joined()
print(list)
// "あいう"
```



## 配列の配列のとき

```swift

extension Array where Element : Collection {

    /// Returns the elements of this collection of collections, concatenated.
    ///
    /// In this example, an array of three ranges is flattened so that the
    /// elements of each range can be iterated in turn.
    ///
    ///     let ranges = [0..<3, 8..<10, 15..<17]
    ///
    ///     // A for-in loop over 'ranges' accesses each range:
    ///     for range in ranges {
    ///       print(range)
    ///     }
    ///     // Prints "0..<3"
    ///     // Prints "8..<10"
    ///     // Prints "15..<17"
    ///
    ///     // Use 'joined()' to access each element of each range:
    ///     for index in ranges.joined() {
    ///         print(index, terminator: " ")
    ///     }
    ///     // Prints: "0 1 2 8 9 15 16"
    ///
    /// - Returns: A flattened view of the elements of this
    ///   collection of collections.
    ///
    /// - SeeAlso: `flatMap(_:)`, `joined(separator:)`
    public func joined() -> FlattenCollection<Array<Element>>
}
```

```swift

/// Returns the concatenated elements of this sequence of sequences,
    /// inserting the given separator between each element.
    ///
    /// This example shows how an array of `[Int]` instances can be joined, using
    /// another `[Int]` instance as the separator:
    ///
    ///     let nestedNumbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    ///     let joined = nestedNumbers.joined(separator: [-1, -2])
    ///     print(Array(joined))
    ///     // Prints "[1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]"
    ///
    /// - Parameter separator: A sequence to insert between each of this
    ///   sequence's elements.
    /// - Returns: The joined sequence of elements.
    ///
    /// - SeeAlso: `joined()`
    public func joined<Separator : Sequence where Separator.Iterator.Element == Iterator.Element.Iterator.Element>(separator: Separator) -> JoinedSequence<Array<Element>>
```

### 使い方

単に結合するとき → `flatMap`

```swift
let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(arrayOfArray.joined().map { $0 })
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(Array(arrayOfArray.joined()))
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
```

入れ子の配列間になにか挟み込みたい場合は`separator`を配列で指定する

```swift

let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(arrayOfArray.joined(separator: [-1, -2]).map { $0 })
// [1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]

print(Array(arrayOfArray.joined(separator: [-1, -2])))
// [1, 2, 3, -1, -2, 4, 5, 6, -1, -2, 7, 8, 9]
```

----

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

```swift
extension String {
    func join (_ seq: [String]) -> String {
        return seq.joined(separator: self)
    }
}
```
と宣言して、以下のように使えます。

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

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

# `split`

- 要素で指定

```swift

    /// Returns the longest possible subsequences of the collection, in order,
    /// around elements equal to the given element.
    ///
    /// The resulting array consists of at most `maxSplits + 1` subsequences.
    /// Elements that are used to split the collection are not returned as part
    /// of any subsequence.
    ///
    /// The following examples show the effects of the `maxSplits` and
    /// `omittingEmptySubsequences` parameters when splitting a string at each
    /// space character (" "). The first use of `split` returns each word that
    /// was originally separated by one or more spaces.
    ///
    ///     let line = "BLANCHE:   I don't want realism. I want magic!"
    ///     print(line.characters.split(separator: " ")
    ///                          .map(String.init))
    ///     // Prints "["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"
    ///
    /// The second example passes `1` for the `maxSplits` parameter, so the
    /// original string is split just once, into two new strings.
    ///
    ///     print(line.characters.split(separator: " ", maxSplits: 1)
    ///                           .map(String.init))
    ///     // Prints "["BLANCHE:", "  I don\'t want realism. I want magic!"]"
    ///
    /// The final example passes `false` for the `omittingEmptySubsequences`
    /// parameter, so the returned array contains empty strings where spaces
    /// were repeated.
    ///
    ///     print(line.characters.split(separator: " ", omittingEmptySubsequences: false)
    ///                           .map(String.init))
    ///     // Prints "["BLANCHE:", "", "", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"
    ///
    /// - Parameters:
    ///   - separator: The element that should be split upon.
    ///   - maxSplits: The maximum number of times to split the collection, or
    ///     one less than the number of subsequences to return. If
    ///     `maxSplits + 1` subsequences are returned, the last one is a suffix
    ///     of the original collection containing the remaining elements.
    ///     `maxSplits` must be greater than or equal to zero. The default value
    ///     is `Int.max`.
    ///   - omittingEmptySubsequences: If `false`, an empty subsequence is
    ///     returned in the result for each consecutive pair of `separator`
    ///     elements in the collection and for each instance of `separator` at
    ///     the start or end of the collection. If `true`, only nonempty
    ///     subsequences are returned. The default value is `true`.
    /// - Returns: An array of subsequences, split from this collection's
    ///   elements.
    public func split(separator: Element, maxSplits: Int = default, omittingEmptySubsequences: Bool = default) -> [ArraySlice<Element>]

```

- 条件で指定

```swift

    /// Returns the longest possible subsequences of the collection, in order,
    /// that don't contain elements satisfying the given predicate.
    ///
    /// The resulting array consists of at most `maxSplits + 1` subsequences.
    /// Elements that are used to split the sequence are not returned as part of
    /// any subsequence.
    ///
    /// The following examples show the effects of the `maxSplits` and
    /// `omittingEmptySubsequences` parameters when splitting a string using a
    /// closure that matches spaces. The first use of `split` returns each word
    /// that was originally separated by one or more spaces.
    ///
    ///     let line = "BLANCHE:   I don't want realism. I want magic!"
    ///     print(line.characters.split(whereSeparator: { $0 == " " })
    ///                          .map(String.init))
    ///     // Prints "["BLANCHE:", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"
    ///
    /// The second example passes `1` for the `maxSplits` parameter, so the
    /// original string is split just once, into two new strings.
    ///
    ///     print(
    ///         line.characters.split(
    ///             maxSplits: 1, whereSeparator: { $0 == " " }
    ///             ).map(String.init))
    ///     // Prints "["BLANCHE:", "  I don\'t want realism. I want magic!"]"
    ///
    /// The final example passes `false` for the `omittingEmptySubsequences`
    /// parameter, so the returned array contains empty strings where spaces
    /// were repeated.
    ///
    ///     print(line.characters.split(omittingEmptySubsequences: false, whereSeparator: { $0 == " " })
    ///                           .map(String.init))
    ///     // Prints "["BLANCHE:", "", "", "I", "don\'t", "want", "realism.", "I", "want", "magic!"]"
    ///
    /// - Parameters:
    ///   - maxSplits: The maximum number of times to split the collection, or
    ///     one less than the number of subsequences to return. If
    ///     `maxSplits + 1` subsequences are returned, the last one is a suffix
    ///     of the original collection containing the remaining elements.
    ///     `maxSplits` must be greater than or equal to zero. The default value
    ///     is `Int.max`.
    ///   - omittingEmptySubsequences: If `false`, an empty subsequence is
    ///     returned in the result for each pair of consecutive elements
    ///     satisfying the `isSeparator` predicate and for each element at the
    ///     start or end of the collection satisfying the `isSeparator`
    ///     predicate. The default value is `true`.
    ///   - isSeparator: A closure that takes an element as an argument and
    ///     returns a Boolean value indicating whether the collection should be
    ///     split at that element.
    /// - Returns: An array of subsequences, split from this collection's
    ///   elements.
    public func split(maxSplits: Int = default, omittingEmptySubsequences: Bool = default, whereSeparator isSeparator: (Element) throws -> Bool) rethrows -> [ArraySlice<Element>]
```

## 使い方


```swift

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

// 空の配列を許容しない
print(array.split(separator: 1).map { [Int]($0) })
// [[7, 2], [2], [3, 2, 3, 4], [5]]

// 空の配列を許容する
print(array.split(separator: 1, omittingEmptySubsequences: false).map { [Int]($0) })
// [[7, 2], [2], [], [3, 2, 3, 4], [5]]

// 偶数の要素で分割（条件指定）
print(array.split { $0 % 2 == 0 }.map { [Int]($0) })
// [[7], [1], [1, 1, 3], [3], [1, 5]]

// コンマで分割
let line = "hoge,piyo,foo,baa"
print(line.characters.split { $0 == "," }.map(String.init))
// ["hoge", "piyo", "foo", "baa"]
```

# `flatMap`

```swift

    /// Returns an array containing the concatenated results of calling the
    /// given transformation with each element of this sequence.
    ///
    /// Use this method to receive a single-level collection when your
    /// transformation produces a sequence or collection for each element.
    ///
    /// In this example, note the difference in the result of using `map` and
    /// `flatMap` with a transformation that returns an array.
    ///
    ///     let numbers = [1, 2, 3, 4]
    /// 
    ///     let mapped = numbers.map { Array(count: $0, repeatedValue: $0) }
    ///     // [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
    /// 
    ///     let flatMapped = numbers.flatMap { Array(count: $0, repeatedValue: $0) }
    ///     // [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
    ///
    /// In fact, `s.flatMap(transform)`  is equivalent to
    /// `Array(s.map(transform).joined())`.
    ///
    /// - Parameter transform: A closure that accepts an element of this
    ///   sequence as its argument and returns a sequence or collection.
    /// - Returns: The resulting flattened array.
    ///
    /// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
    ///   and *n* is the length of the result.
    /// - SeeAlso: `joined()`, `map(_:)`
    public func flatMap<SegmentOfResult : Sequence>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element]
```

（参考）

```swift

    /// Returns an array containing the non-`nil` results of calling the given
    /// transformation with each element of this sequence.
    ///
    /// Use this method to receive an array of nonoptional values when your
    /// transformation produces an optional value.
    ///
    /// In this example, note the difference in the result of using `map` and
    /// `flatMap` with a transformation that returns an optional `Int` value.
    ///
    ///     let possibleNumbers = ["1", "2", "three", "///4///", "5"]
    /// 
    ///     let mapped: [Int?] = numbers.map { str in Int(str) }
    ///     // [1, 2, nil, nil, 5]
    /// 
    ///     let flatMapped: [Int] = numbers.flatMap { str in Int(str) }
    ///     // [1, 2, 5]
    ///
    /// - Parameter transform: A closure that accepts an element of this
    ///   sequence as its argument and returns an optional value.
    /// - Returns: An array of the non-`nil` results of calling `transform`
    ///   with each element of the sequence.
    ///
    /// - Complexity: O(*m* + *n*), where *m* is the length of this sequence
    ///   and *n* is the length of the result.
    public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
```

## 使い方

```
// 結合
let arrayOfArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(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]
print(array.split(separator: 1).flatMap { $0 })
// [7, 2, 2, 3, 2, 3, 4, 5]
```

- `map`と`flatMap`の挙動の違い

```swift

let numbers = [1, 2, 3, 4]

let mapped = numbers.map { Array(repeating: $0, count: $0) }
print(mapped)
// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]

let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
print(flatMapped)
// [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
```