Edited at

SequenceTypeとなったEnumerateについて

More than 1 year has passed since last update.


About

Swiftでは、配列内のポジションを知ることができるenumarated()とよばれる関数があります。

今回はこれについてまとめてました。


What it means

enumerateは "一覧になったものに1つずつ名前を付ける"という意味があります。


Available

iOS7.0から利用できます。

Swift3.0以前はSequenceTypeにenumerate()でしたが,

Swift3からenumerated()へと変更になりました。


Sources


Example.1

次のような例では配列の要素と一緒にインデックスが出力されます。


Before

let fruits = ["Apples","Lemons","Oranges"]

var index = 0
for fruit in fruits {
print("Index: \(index), fruit: \(fruit)")
index += 1
}

// Index: 0, fruit: Apples
// Index: 1, fruit: Lemons
// Index: 2, fruit: Oranges


ループを繰り返すたびに+1を加えながら、fruitに対応するインデックスも表示されます。

しかし、これだと直接Intを扱うので若干違和感がありますね。

そこで早速enumerated()の出番です。


After

let fruits = ["Apples","Lemons","Oranges"]

for (index, fruit) in fruits.enumerated() {
print("Index: \(index), fruit: \(fruit)")
}

// Index: 0, fruit: Apples
// Index: 1, fruit: Lemons
// Index: 2, fruit: Oranges



Example.2

(index, fruit)のように,型の異なる複数の値は, 以下のようにタプル(Tpule)で記述することが可能です。

let fruits = ["Apples","Lemons","Oranges"]

for item in fruits.enumerated() {
print(item.offset ,item.element)
}

// 0 Apples
// 1 Lemons
// 2 Oranges

それぞれドットを使って,インデックス.offset, 配列の要素.elementで参照できます。


Example.3

for-inのような高速列挙を使わずmapで表現する方法もあります。


その1

let fruitList = fruits.enumerated().map { "\($0.0):\($0.1)" }

print(fruitList)

// ["0:Apples", "1:Lemons", "2:Oranges"]


あるいは


その2

let fruitList = fruits.enumerated().map { "\($0.offset):\($0.element)" }

print(fruitList)

// ["0:Apples", "1:Lemons", "2:Oranges"]


そのため、map関数内クロージャーのように定義すれば便利ですね

let fruitList = fruits.enumerated().map { item in

print(item.offset, item.element)
}

// 0 Apples
// 1 Lemons
// 2 Oranges


Reference

AppleのAPIには次のように記載されています。


Swift3.0

    /// Returns a sequence of pairs (*n*, *x*), where *n* represents a

/// consecutive integer starting at zero, and *x* represents an element of
/// the sequence.
///
/// This example enumerates the characters of the string "Swift" and prints
/// each character along with its place in the string.
///
/// for (n, c) in "Swift".characters.enumerated() {
/// print("\(n): '\(c)'")
/// }
/// // Prints "0: 'S'"
/// // Prints "1: 'w'"
/// // Prints "2: 'i'"
/// // Prints "3: 'f'"
/// // Prints "4: 't'"
///
/// When enumerating a collection, the integer part of each pair is a counter
/// for the enumeration, not necessarily the index of the paired value.
/// These counters can only be used as indices in instances of zero-based,
/// integer-indexed collections, such as `Array` and `ContiguousArray`. For
/// other collections the counters may be out of range or of the wrong type
/// to use as an index. To iterate over the elements of a collection with its
/// indices, use the `zip(_:_:)` function.
///
/// This example iterates over the indices and elements of a set, building a
/// list of indices of names with five or fewer letters.
///
/// let names: Set = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
/// var shorterIndices: [SetIndex<String>] = []
/// for (i, name) in zip(names.indices, names) {
/// if name.characters.count <= 5 {
/// shorterIndices.append(i)
/// }
/// }
///
/// Now that the `shorterIndices` array holds the indices of the shorter
/// names in the `names` set, you can use those indices to access elements in
/// the set.
///
/// for i in shorterIndices {
/// print(names[i])
/// }
/// // Prints "Sofia"
/// // Prints "Mateo"
///
/// - Returns: A sequence of pairs enumerating the sequence.
public func enumerated() -> EnumeratedSequence<Array<Element>>


Swift2.3

extension SequenceType {

/// Returns a lazy `SequenceType` containing pairs (*n*, *x*), where
/// *n*s are consecutive `Int`s starting at zero, and *x*s are
/// the elements of `base`:
///
/// > for (n, c) in "Swift".characters.enumerate() {
/// print("\(n): '\(c)'")
/// }
/// 0: 'S'
/// 1: 'w'
/// 2: 'i'
/// 3: 'f'
/// 4: 't'
@warn_unused_result
public func enumerate() -> EnumerateSequence<Self>
}


Finally

書き方については,他にもいろんなパターンがあると思います。

他にも「こんな方法があるよ!」というアドバイスがございましたら、

是非ご教示頂けると幸いです。