Thanks for the answer @nnnnnnnn
"What does SortDescriptor
provide that a (Element) -> T
closure wouldn't
Mostly:
- ability to reverse the sort (because
T
can be anything so unlike a Bool
that you can just invert to revert the sort, if you pass a KeyPath
(which would be turned into a closure as per SE-249) it's not enough to be able to revert the sort
- ability to pass multiple sorting keys (KeyPaths) even if they are KeyPath to properties of different types
But tbh I would already be happy with the stdlib just having a sorted(by: (Element) -> T), using comparator: (T, T) -> Bool
with comparator
defaulting to <
when T: Comparable
. That would not support multiple-keys sorting, but that's a rather rare use case anyway so I'd be ok with this.
- How does this expanded notion of sorting interact with the design of a potential
SortedCollection
protocol and future concrete sorted collections?
I missed that this was a thing in the works. Good point, if we consider having SortedCollection
or other similar concepts in the future, let's wait for those to settle. Is there already some kind of Manifesto started about that?
What kinds of optimizations are enabled by a proposed solution?
I haven't done any in-depth analysis of performance optimization but since SortDescriptor
ends up being just a wrapper to construct a type-erased closure from a KeyPath
, I'm assuming that with optimization enabled on the compiler it wouldn't be less performant that building the closure yourself.
The main point of the proposal is not about improving performance of the sorting algorithm but to improve the API of Collection
by avoiding useless typing in the most common case where you want to sort by a property of Element
, while avoid the risk of error that arise when repeating that property twice in the closure for the current statu-quo
- What about persistence? For example, if I'm displaying a spreadsheet, I might want to sort on multiple columns, but have that be independent of the way my data is stored.
Sorry but I don't see how that question fits with the original topic proposed here? This is a different problem and question, that actually already applies to using closures with the current sort(by:)
API and is not specific to the new API with KeyPath
or SortDescriptor
, is it?
- What other sorting algorithms are we waiting for in the standard library? A partial sort, at minimum, would be valuable for finding the smallest or largest
n
items in a collection.
I see your point, but I'm not sure this is completely relevant to the problem we're trying to solve with this sort(by: [SortDescriptor])
API here. Again, the point of the suggested new sort(by: [SortDescriptor])
API is to be a convenience entry point for the existing sort(by: (Element, Element) -> Bool)
that allows to construct that closure more easily by passing one or multiple KeyPath
(wrapped in a SortDescriptor
… or not if we abandon the SortDescriptor
idea to support multiple-keys sorting and go straight to KeyPath
with single-property sorts)
In the end, I'd agree to drop the SortDescriptor
idea given how it's controversial to add that new type in the stdlib. But would it be acceptable to at least add the one with KeyPath
to the stdlib?
extension Collection {
func sorted<T>(by keyPath: KeyPath<Element, T>, using: (T, T) -> Bool) -> [Element] {
sort(by: { using($0[keyPath: keyPath], $1[keyPath: keyPath]) })
}
func sort<T: Comparable>(by keyPath: KeyPath<Element, T>) -> Element {
sort(by: keyPath, using: <)
}
}