[swift-evolution] [Idea] Add an (Index, Element) sequence to CollectionType

Patrick Pijnappel patrickpijnappel at gmail.com
Sun Dec 27 02:08:04 CST 2015


-- Introduction

There should be a property on CollectionType that returns a sequence of
(Index, Element) tuples.
Currently enumerate() is often used instead, but it is not well suited to
the task and can lead to bugs.



-- Motivation

Using enumerate() instead of an (Index, Element) sequence has two main
problems.
Both arise because enumerate() returns a sequence of (n, Element) tuples,
where n is the element *number*, instead of a sequence of (Index, Element).

1) It doesn't work for collections not indexed by integers.

2) It doesn't do what you might expect in some cases, as indices do not
always start at 0.
For example ArraySlice's indices do not: array[2..<5] starts with index 2.
Consider the following code to take the 2nd half of the array and remove
all empty elements:

var array = [ "", "a", "b", "c", "", "d" ]
var secondHalf = array[array.count/2..<array.count]
for (index, element) in secondHalf.enumerate() {
  if element == "" {
  secondHalf.removeAtIndex(index)
  }
}

This code will crash (ignoring for a moment this should probably be using
filter).



-- Alternatives

The same effect can already be achieved using the following:

for index in collection.indices {
  let element = collection[index]
  // ...
}

However having a dedicated (Index, Element) sequence has the following
advantages:
a) It can help prevent people from using enumerate() inappropriately.
b) It is very common use case that deserves shortening.
c) It can be chained (e.g. to map).



-- Proposed Solution

Add a property/method on CollectionType that returns a sequence of (Index,
Element) tuples.
For example, using a property named indexed:

for (index, element) in collection.indexed {
  // ...
}

This should be the preferred idiom when you want both the index and the
element.

Note that enumerate() does still have valid roles to play:
- When you actually do want the element number, not the index.
- When you have a SequenceType, as it isn't indexed.



-- Implementation

The feature could be entirely implemented using existing constructs:

extension CollectionType {
  var indexed: AnySequence<(Index, Generator.Element)> {
    return AnySequence(indices.lazy.map { ($0, self[$0]) })
  }
}

Alternatively, a dedicated SequenceType and/or GeneratorType could be added.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151227/975f6ca9/attachment.html>


More information about the swift-evolution mailing list