The original example contains a bug which is present on all looping
version/alternative due to the mutating nature of the array. Using the zip
implementation:
var array = [ "", "a", "b", "c", "", "d" ]
var secondHalf = array[array.count/2..<array.count]
for (index, element) in zip(secondHalf.indices, secondHalf) {
if element == "" {
secondHalf.removeAtIndex(index)
}
}
The variable index cycles through 3,4 and 5; but in order to be able to remove
the right element beyond the first removal, the variable index should have
cycled through 3, 4 and 4 (as some elements got shifted after the first
mutation). Mutating the array/list which one loops over is a risky business and
is a nice source of bugs (including infinite loop). If this (Index, Element) is
further investigated, it should consider that one may also want to do a
insert(:atIndex:), and may expect the (Index, Element) to have proper Index but
only for the original Element.
Dany St-Amant
> Le 28 déc. 2015 à 01:06, Kevin Ballard via swift-evolution
> <[email protected]> a écrit :
>
> What you're asking for can already be done with `zip(col.indices, col)`. And
> in my experience the need for this sort of thing is rare enough that there's
> no need to have a dedicated property for it in the stdlib. The few times that
> I've needed this sort of thing, I've always just said
>
> for index in col.indices {
> let elt = col[index]
> // ...
> }
>
> and that's pretty simple. But if I ever did need to map it, I'd just use the
> aforementioned zip() expression.
>
> -Kevin Ballard
>
> On Sun, Dec 27, 2015, at 12:08 AM, Patrick Pijnappel via swift-evolution
> wrote:
>> -- 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.
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>
>
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution