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 
> <swift-evolution@swift.org> 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
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>  
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to