# Add sort overload to Sequence to sort by a Comparable attribute of elements

**URL:** <https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683>\
**Category:** Pitches\
**Tags:** collection, sorting\
**Created:** [June 17, 2020, 6:57pm UTC](https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683 "2020-06-17T18:57:29Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomhamming](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tomhamming/32/12153_2.png) [@tomhamming](https://forums.swift.org/u/tomhamming)\
**Post date:** [June 17, 2020, 6:57pm UTC](https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683/1 "2020-06-17T18:57:29Z")

</div>

Sorting sequences is a really common operation. Swift's `Sequence` type makes this easy with the [`sorted(by:)`](https://developer.apple.com/documentation/swift/sequence/2907222-sorted) method. I think this could be streamlined a little with an overload that takes a transform from `Element` to a `Comparable`:

```swift
extension Sequence {
    func sortedBy<T: Comparable>(_ transform: (Self.Element) throws -> T) rethrows -> [Self.Element] {
        return try self.sorted { (lhs, rhs) -> Bool in
            let l = try transform(lhs)
            let r = try transform(rhs)
            return l < r
        }
    }
}

```

This makes sorting a sequence by one attribute of its elements a little more straightforward. Given a sequence of `Person` structs with `firstName` and `lastName` properties, sorting by `lastName` currently requires:

```swift
let sorted = people.sortedBy({$0.lastName < $1.lastName})

```

With this additional overload, we can simply write:

```swift
let sorted = people.sortedBy({$0.lastName})

```

Addding `sortedByDescending` would allow sorting either way.

If we add this to the [Sorted Collections](https://forums.swift.org/t/sorted-collection-protocol/11738) idea and take a cue from [C#'s similar API](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.thenby?view=netcore-3.1), we could add `.thenBy(transform)` and `.thenByDescending(transform)` and can sort by last and then first name with:

```swift
let sorted = people.sortedBy({$0.lastName}).thenBy({$0.firstName})

```

IMO this reads more clearly than implementing the two-tier sorting with a comparator:

```swift
let sorted = people.sorted { (lhs, rhs) -> Bool in
    return (lhs.lastName == rhs.lastName ? lhs.firstName < rhs.firstName : lhs.lastName < rhs.lastName)
    }

```

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [June 17, 2020, 7:07pm UTC](https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683/2 "2020-06-17T19:07:39Z")

</div>

Hi! Something like this has been discussed several times. You might find the following pitch to be edifying:

> [@Map Sorting](https://forums.swift.org/t/map-sorting/21421):
>
> Map Sorting Authors: [Anthony Latsis](https://github.com/AnthonyLatsis), [Cal Stephens](https://github.com/calda) Status: Awaiting Review Implementation: [apple/swift#23156](https://github.com/apple/swift/pull/23156)Introduction This proposal presents an addition to the Standard Library that makes it easy to sort a collection over some set of mapped values, provided via a transform closure or KeyPath, in a way that is ergonomic, idiomatic, and performant. Motivation To sort a Collection, you're currently required to specify an areInIncreasingOrder predicate of the form (Element, Element) -\> B…

Similarly:

> [@Sort \`Collection\` using \`KeyPath\`](https://forums.swift.org/t/sort-collection-using-keypath/14554):
>
> Hey everybody — I'd like to pitch and socialize a new method for sorting Collections using a KeyPath. Today, to sort a Collection of non-Comparable elements, we write a closure that returns whether or not two elements areInIncreasingOrder: [[1, 2, 3], [1], [1, 2]].sorted(by: { $0.count \< $1.count }) // returns [[1], [1, 2], [1, 2, 3]] This has a few features that you could consider "pain points": The call site doesn't form a grammatical english phrase. [[1]](https://swift.org/documentation/api-design-guidelines/#strive-for-fluent-usage) It's relatively easy to mix up \< …

In the latter thread, @ben-cohen (from the core team) writes:

> I think there is a lot of room for ergonomic improvements to sorting, so it's great to see this!
> 
> I would suggest, though, taking a step back and thinking about all the different aspects of this as a a whole. Individual targeted fixes are nice, but risk API sprawl when they handle some cases not others, leading to other targeted fixes.
> 
> Some topics to consider:
> 
> - key paths vs closures
> - note, localized/caseless sorting is also painful, but at least doable, with closure-based arguments
> - including weighing the pros/cons of parametrizing with ascending/descending choice (not a technique that sits well with the existing idioms used in the std lib)
> 
> - sorting by a sequence of comparators, lexicographically
> - partial sorting/partitioning
> 
> A great place to start would be a comparison with the existing APIs to be found in other places i.e. Java, Ruby, Cocoa (which has all sorts of different ways to sort, [`sortUsingDescriptors`](https://developer.apple.com/documentation/foundation/nsmutablearray/1410745-sortusingdescriptors) being particularly of interest).

---

<div class="post-metadata">

**Author:** ![tomhamming](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tomhamming/32/12153_2.png) [@tomhamming](https://forums.swift.org/u/tomhamming)\
**Post date:** [June 17, 2020, 7:30pm UTC](https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683/3 "2020-06-17T19:30:38Z")

</div>

Ah, thanks! I searched briefly for existing pitches but didn't find those.

---

<div class="post-metadata">

**Author:** ![GreatApe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/greatape/32/2640_2.png) [@GreatApe](https://forums.swift.org/u/GreatApe)\
**Post date:** [June 18, 2020, 2:01pm UTC](https://forums.swift.org/t/add-sort-overload-to-sequence-to-sort-by-a-comparable-attribute-of-elements/37683/4 "2020-06-18T14:01:24Z")

</div>

This would definitely be nice, I often make versions of this. I think it makes sense even if the entire sort system is overhauled, we will always want this.
