LoginSignup
29
27

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-11-18

この記事について

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

  • flatten
  • joinWithSeparator
  • split
  • flatMap(追記)

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

flatten


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文で回す際はそういった処理は不要です。


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


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を挿入します。
注意するべきところは、SeparatorSequenceType、つまり、配列であるというところです。


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


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を返してくれます。

使い方


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

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

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


extension String {
    func join (seq: [String]) -> String {
        return seq.joinWithSeparator(self)
    }
}

と宣言して、


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

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

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

split

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


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

使い方


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]]

// *** 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]]

// *** 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]]

上記の組み合わせで出来ること

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


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]

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


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が便利過ぎるにあるような、nilの扱い以外にもflatMapは便利過ぎでした。

flatMap

その1 - nilの扱いのflatMap


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


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]
}

使い方


// 結合
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]

今まで、


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())

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

29
27
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
27