<div style="white-space:pre-wrap">If these are to be added, I'd advocate for renaming `index(of:)` and `index(where:)` to `firstIndex(of:)` and `firstIndex(where:)`, respectively.<br></div><br><div class="gmail_quote"><div dir="ltr">On Tue, May 10, 2016 at 13:54 Nate Cook via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">I've needed these in the past and used them in other languages—any feedback on this idea?</p><div><hr style="background-image:url();background-color:rgb(255,255,255);border:0px none;color:rgb(204,204,204);min-height:4px;padding:0px;font-family:Helvetica,arial,sans-serif;font-size:14px;margin-top:0px!important;background-position:0px 0px;background-repeat:repeat no-repeat"><h1 style="margin:20px 0px 10px;padding:0px;font-family:Helvetica,arial,sans-serif;background-color:rgb(255,255,255)">Add <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">last(where:)</code> and <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">lastIndex(where:)</code> Methods to Bidirectional Collections</h1><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">The standard library should include methods for finding the last element of a bidirectional collection that matches a predicate, along with the index of that element.</p><h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);font-family:Helvetica,arial,sans-serif;background-color:rgb(255,255,255)">Motivation</h2><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">The standard library currently has (or will soon have) methods that perform a linear search from the beginning of a collection to find an element that matches a predicate:</p><div style="font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)"><pre style="margin-top:0.5em;margin-bottom:0.5em;background-color:rgb(245,242,240);border:1px solid rgb(204,204,204);font-size:13px;line-height:1.5;overflow:auto;padding:1em;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal"><code style="margin:0px;padding:0px;border:none;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;background-image:none;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5"><span style="color:rgb(0,119,170)">let</span> a <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">=</span> <span style="color:rgb(153,153,153)">[</span><span style="color:rgb(153,0,85)">20</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">30</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">10</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">40</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">20</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">30</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">10</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">40</span><span style="color:rgb(153,153,153)">,</span> <span style="color:rgb(153,0,85)">20</span><span style="color:rgb(153,153,153)">]</span>
a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">first</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(0,119,170)">where</span><span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,153,153)">{</span> $<span style="color:rgb(153,0,85)">0</span> <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">></span> <span style="color:rgb(153,0,85)">25</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 30</span>
a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">index</span><span style="color:rgb(153,153,153)">(</span>of<span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,0,85)">10</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 2</span>
a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">index</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(0,119,170)">where</span><span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,153,153)">{</span> $<span style="color:rgb(153,0,85)">0</span> <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">></span> <span style="color:rgb(153,0,85)">25</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 1</span></code></pre></div><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">Unfortunately, there is no such method that searches from the end of a bidirectional collection. Finding the last of particular kind of element has multiple applications, particularly with text, such as wrapping a long string into lines of a maximum length or trimming whitespace from the beginning and end of a string.</p><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">This limitation can be worked around by using the methods above on the reversed collection, but the resulting code is truly dreadful. For example, to find the corresponding last index to <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">a.index(where: { $0 > 25 })</code>, this unholy incantation is required:</p><div style="font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)"><pre style="margin-top:0.5em;margin-bottom:0.5em;background-color:rgb(245,242,240);border:1px solid rgb(204,204,204);font-size:13px;line-height:1.5;overflow:auto;padding:1em;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal"><code style="margin:0px;padding:0px;border:none;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;background-image:none;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5"><span style="color:rgb(153,153,153)">(</span>a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">reversed</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(153,153,153)">)</span><span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">index</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(0,119,170)">where</span><span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,153,153)">{</span> $<span style="color:rgb(153,0,85)">0</span> <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">></span> <span style="color:rgb(153,0,85)">25</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span><span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">?</span><span style="color:rgb(153,153,153)">.</span>base<span style="color:rgb(153,153,153)">)</span><span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">flatMap</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(153,153,153)">{</span> a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">index</span><span style="color:rgb(153,153,153)">(</span>before<span style="color:rgb(153,153,153)">:</span> $<span style="color:rgb(153,0,85)">0</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span></code></pre></div><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">Wat.</p><h2 style="margin:20px 0px 10px;padding:0px;font-size:24px;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(204,204,204);font-family:Helvetica,arial,sans-serif;background-color:rgb(255,255,255)">Proposed solution</h2><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">Bidirectional collections should include three new methods for symmetry with the existing forward-searching APIs: <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">last(where:)</code>, <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">lastIndex(where:)</code>, and <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">lastIndex(of:)</code>, specifically for collections of <code style="margin:0px 2px;padding:0px 5px;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Equatable</code> elements.</p><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">These additions would remove the need for searching in a reversed collection and allow code like the following:</p><div style="font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)"><pre style="margin-top:0.5em;margin-bottom:0.5em;background-color:rgb(245,242,240);border:1px solid rgb(204,204,204);font-size:13px;line-height:1.5;overflow:auto;padding:1em;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal"><code style="margin:0px;padding:0px;border:none;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;background-image:none;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5">a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">last</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(0,119,170)">where</span><span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,153,153)">{</span> $<span style="color:rgb(153,0,85)">0</span> <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">></span> <span style="color:rgb(153,0,85)">25</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 40</span>
a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">lastIndex</span><span style="color:rgb(153,153,153)">(</span>of<span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,0,85)">10</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 6</span>
a<span style="color:rgb(153,153,153)">.</span><span style="color:rgb(221,74,104)">lastIndex</span><span style="color:rgb(153,153,153)">(</span><span style="color:rgb(0,119,170)">where</span><span style="color:rgb(153,153,153)">:</span> <span style="color:rgb(153,153,153)">{</span> $<span style="color:rgb(153,0,85)">0</span> <span style="color:rgb(166,127,89);background-color:rgba(255,255,255,0.498039);background-position:initial initial;background-repeat:initial initial">></span> <span style="color:rgb(153,0,85)">25</span> <span style="color:rgb(153,153,153)">}</span><span style="color:rgb(153,153,153)">)</span> <span style="color:rgb(112,128,144)">// 7</span></code></pre></div><p style="margin:15px 0px;font-family:Helvetica,arial,sans-serif;font-size:14px;background-color:rgb(255,255,255)">Much better!</p></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>