<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">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.</div><div class=""><br class=""></div><div class="">If we can guarantee tail-end removal is safe, a minimalist’s solution could be:</div><div class=""><br class=""></div><div class="">extension&nbsp;RangeReplaceableCollection&nbsp;{<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>mutating&nbsp;func&nbsp;remove&lt;S:Sequence&nbsp;where&nbsp;S.Iterator.Element == Index&gt;(at indexes:&nbsp;S) {<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>for&nbsp;idx&nbsp;in&nbsp;indexes.sorted(isOrderedBefore:&nbsp;&gt;) {<br class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>remove(at: idx)<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class="">}</div><div class=""><br class=""></div><div class="">Maybe with Array having a more optimal implementation if those sorted indexes form a continuous range.</div><div class=""><br class=""></div><div class="">Karl<br class=""><br class=""></div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On 19 Jun 2016, at 06:58, Saagar Jha &lt;<a href="mailto:saagarjha28@gmail.com" class="">saagarjha28@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><p class="">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”. <code class="">filter</code>, <code class="">enumerated</code> (to get indices), and <code class="">map</code> (to go back to elements) are more than up to the task. Plus, this is much more efficient.</p>
<pre class=""><code class="">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]"
</code></pre><p class="">Adding it to the standard library might be useful, but it’s not as hard as it looks.</p>
<br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Sat, Jun 18, 2016 at 9:09 PM Karl via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">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.<br class="">
<br class="">
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.<br class="">
<br class="">
A näive implementation might look like this:<br class="">
<br class="">
for index in indexesToRemove {<br class="">
&nbsp; &nbsp; myArray.remove(at: index)<br class="">
}<br class="">
<br class="">
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:<br class="">
<br class="">
extension RangeReplaceableCollection where Index:Hashable, Self:BidirectionalIndexable {<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; mutating func remove(at indexes: Set&lt;Index&gt;) {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var removed : IndexDistance = 0<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for idx in indexes.sorted() {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; remove(at: index(idx, offsetBy: -removed))<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; removed = removed.advanced(by: 1)<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
}<br class="">
<br class="">
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.<br class="">
<br class="">
Karl<br class="">
<br class="">
<br class="">
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div></div><div dir="ltr" class="">-- <br class=""></div><div data-smartmail="gmail_signature" class=""><div dir="ltr" class="">-Saagar Jha</div></div>
</div></blockquote></div><br class=""></body></html>