Scratch that: it should still be a Set and Index should still be Hashable. 
Otherwise the order of the indexes could be important and there may be 
duplicates. That’s a level of sophistication where you should know how about 
index invalidation while mutating and can do it manually.

extension RangeReplaceableCollection where Index : Hashable {

        mutating func remove(at indexes: Set<Index>) {

                for idx in indexes.sorted(isOrderedBefore: >) {
                        remove(at: idx)
                }
        }
}

It’s not actually O(n^2) - it’s O(m*n), where m is never larger than n, and 
likely much smaller if n is large. Otherwise, you should probably use an 
inclusive filter and create a new instance, rather than than removing most of 
your large numbers of elements in-place.

So it’s probably better to loop over m. Given that, I’m not sure how we’d 
improve on the O(n) remove-at-index. That said, I’m seeing lots of weirdness in 
Xcode 8 (which may just be my machine), so I’m not really certain what 
MutableCollection even provides — apparently it supports in-place ’sort’ (via 
CMD+click), but it’s not in auto-complete and trying to use it is a compile 
error.

Karl

> On 19 Jun 2016, at 07:59, Karl <[email protected]> wrote:
> 
> What exactly are the guarantees for index safety across mutations? Both 
> Collection and Indexable stop short of making any kind of guarantees about 
> what happens to indexes after you mutate. For example, popFirst() has the 
> potential to invalidate all stored indexes, but you wouldn’t know that if you 
> were just working in terms of Collection.
> 
> If we can guarantee tail-end removal is safe, a minimalist’s solution could 
> be:
> 
> extension RangeReplaceableCollection {
> 
>       mutating func remove<S:Sequence where S.Iterator.Element == Index>(at 
> indexes: S) {
> 
>               for idx in indexes.sorted(isOrderedBefore: >) {
>                       remove(at: idx)
>               }
>       }
> }
> 
> Maybe with Array having a more optimal implementation if those sorted indexes 
> form a continuous range.
> 
> Karl
> 
> 
> 
>> On 19 Jun 2016, at 06:58, Saagar Jha <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> This isn’t actually that complex, especially if you ditch the “C-style” for 
>> loop algorithm and switch it to, as you mentioned, “filtering code”. filter, 
>> enumerated (to get indices), and map (to go back to elements) are more than 
>> up to the task. Plus, this is much more efficient.
>> 
>> var myArray = [0, 1, 2]
>> let indices: Set = [0, 1]
>> myArray = myArray.enumerated().filter {
>>     return !indices.contains($0.offset)
>> }.map {
>>     return $0.element // to get the elements back
>> }
>> print(myArray) // prints “[2]"
>> Adding it to the standard library might be useful, but it’s not as hard as 
>> it looks.
>> 
>> 
>> 
>> On Sat, Jun 18, 2016 at 9:09 PM Karl via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> So like most good pitches, this one comes about because of a bug I recently 
>> fixed which seems common and subtle enough that I think it would be nice to 
>> include in the standard library.
>> 
>> Removing a collection of elements at once from a collection. You might want 
>> to do this in some kind of advanced filtering code. In my case, our code was 
>> merging adjacent elements in-place, and storing a list of indexes that were 
>> no longer required because they were now part of a merged element, and then 
>> we cleaned up the duplicates by removing those indexes.
>> 
>> A näive implementation might look like this:
>> 
>> for index in indexesToRemove {
>>     myArray.remove(at: index)
>> }
>> 
>> However, as the array is mutated, those indexes won’t make sense any more. 
>> You’ll end up with invalid results - for example, if you have the array 
>> [0,1,2] and indexesToRemove is [0,1], your resulting array will actually be 
>> [1] (not [2], as expected). Actually removing a batch of indexes is subtly 
>> more complex. Here’s my generic implementation:
>> 
>> extension RangeReplaceableCollection where Index:Hashable, 
>> Self:BidirectionalIndexable {
>> 
>>         mutating func remove(at indexes: Set<Index>) {
>>                 var removed : IndexDistance = 0
>>                 for idx in indexes.sorted() {
>>                         remove(at: index(idx, offsetBy: -removed))
>>                         removed = removed.advanced(by: 1)
>>                 }
>>         }
>> }
>> 
>> I think it would be nice to have this in the standard library. I think it’s 
>> a reasonably common problem and it’d be nice to make it easier for people.
>> 
>> Karl
>> 
>> 
>> _______________________________________________
>> 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>
>> -- 
>> -Saagar Jha
> 

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to