[swift-evolution] (Draft) Add last(where:) and lastIndex(where:) methods

Nate Cook natecook at gmail.com
Tue May 10 18:52:58 CDT 2016

Thanks Hooman! Those do look like useful extensions. I think the proposal should stay focused on the APIs it includes already.

> On May 10, 2016, at 4:18 PM, Hooman Mehr <hooman at mac.com> wrote:
> I agree with adding more such API’s. 
> Look at this gist <https://gist.github.com/hooman/e77cc0e955a1db672ae49e45b0038d04> for an implementation of a few more of what I find useful. You can add them to your proposal if you like them and I will be able to help better shape it up. Here is a summary:
> public func offset(of index: Index) -> IndexDistance
> public func index(atOffset offset: IndexDistance) -> Index

I like these, but I doubt they would get much traction, since they're essentially substituting startIndex into existing methods. I have thought it would be nice to have startIndex as the default parameter to those methods, though, so you could write either of these:

	let i = c.index(c.startIndex, offsetBy: 5)		// current
	let i = c.index(offsetBy: 5)				// nice addition

> public func index(of element: Iterator.Element, from firstIndex: Index) -> Index?
> public func index(from firstIndex: Index, where predicate: @noescape (Iterator.Element) throws -> Bool) rethrows -> Index?

I have the same reaction to these. Because indices are shared between collections and slices, instead of using a starting index, Swift's collection operations can just work on a slice. So instead of calling

	let i = c.index(of: "A", from: firstIndex)

you can call

	let i = c.suffix(from: firstIndex).index(of: "A")

> public func index<C: Collection where ...>(of elementSequence: C) -> Index?
> public func index<C: Collection where ...>(of elementSequence: C, from firstIndex: Index) -> Index?

These methods we don't have at all currently, and could really use! I would definitely support a proposal for finding a subsequence of a collection. There are several algorithms beyond the naive approach, so it would be interesting to see if / how a proposal could use those in a generic context.

Thanks again!

> Look at the comments for the example usage. For `offset` function, see the source code for usage.
> Hooman
>> On May 10, 2016, at 11:54 AM, Nate Cook via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> I've needed these in the past and used them in other languages—any feedback on this  idea?
>> Add last(where:) and lastIndex(where:) Methods to Bidirectional Collections
>> 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.
>> Motivation
>> 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:
>> let a = [20, 30, 10, 40, 20, 30, 10, 40, 20]
>> a.first(where: { $0 > 25 })         // 30
>> a.index(of: 10)                     // 2
>> a.index(where: { $0 > 25 })         // 1
>> 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.
>> 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 a.index(where: { $0 > 25 }), this unholy incantation is required:
>> (a.reversed().index(where: { $0 > 25 })?.base).flatMap({ a.index(before: $0) })
>> Wat.
>> Proposed solution
>> Bidirectional collections should include three new methods for symmetry with the existing forward-searching APIs: last(where:), lastIndex(where:), and lastIndex(of:), specifically for collections of Equatable elements.
>> These additions would remove the need for searching in a reversed collection and allow code like the following:
>> a.last(where: { $0 > 25 })          // 40
>> a.lastIndex(of: 10)                 // 6
>> a.lastIndex(where: { $0 > 25 })     // 7
>> Much better!
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160510/b2ea9c7d/attachment-0001.html>

More information about the swift-evolution mailing list