#この記事について
配列の配列で出来ることや、配列の配列の作り方についてまとめてみました。
- 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
を挿入します。
注意するべきところは、Separator
もSequenceType
、つまり、配列であるというところです。
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())
としていたのを随分すっきりと書けるようになりました。