Add max
, min
and lexicographicallyPrecedes
using SortComparator
- Proposal: SF-NNNN
- Authors: Mateus Rodrigues
- Review Manager: TBD
- Status: Pitch
- Implementation:
Introduction
Foundation has the method sorted(using:)
to sort sequences using objects conforming to SortComparator
, such as KeyPathComparator
:
let people: [Person] = [...]
let peopleSortedByAge = people.sorted(using: KeyPathComparator(\.age))
This method calls sorted(by:)
, which uses a (Self.Element, Self.Element) throws -> Bool)
closure to sort the sequence elements.
The Sequence protocol has two other methods that uses the same closure type, max(by:)
, min(by:)
and lexicographicallyPrecedes(_:by:)
:
let oldestPerson = people.max(by: {
$0.age < $1.age
}
let youngestPerson = people.min(by: {
$0.age < $1.age
})
let isFirstGroupYounger = firstGroup.lexicographicallyPrecedes(secondGroup, by: { $0.age < $1.age })
These methods could benefit from counterparts using SortComparator
as well.
Proposed Solution
Introduce max(using:)
, min(using:)
and lexicographicallyPrecedes(_:using:)
methods to use a comparator in these operations.
let oldestPerson = people.max(using: KeyPathComparator(\.age))
let youngestPerson = people.min(using: KeyPathComparator(\.age))
let isFirstGroupYounger = firstGroup.lexicographicallyPrecedes(secondGroup, using: KeyPathComparator(\.age))
Detailed Design
extension Sequence {
/// Returns the maximum element in the sequence, using the given comparator
/// to compare elements.
///
/// - Parameters:
/// - comparator: the comparator to use in ordering elements
/// - Returns: The sequence's maximum element, according to `comparator`.
/// If the sequence has no elements, returns `nil`.
public func max(using comparator: some SortComparator<Element>) -> Element? {
return self.max {
comparator.compare($0, $1) == .orderedAscending
}
}
/// Returns the minimum element in the sequence, using the given comparator as
/// to compare elements.
///
/// - Parameters:
/// - comparator: the comparator to use in ordering elements
/// - Returns: The sequence's minimum element, according to `comparator`.
/// If the sequence has no elements, returns `nil`.
public func min(using comparator: some SortComparator<Element>) -> Element? {
return self.min {
comparator.compare($0, $1) == .orderedAscending
}
}
/// Returns a Boolean value indicating whether the sequence precedes another
/// sequence in a lexicographical (dictionary) ordering, using the given
/// comparator to compare elements.
///
/// - Parameters:
/// - other: A sequence to compare to this sequence.
/// - comparator: the comparator to use in ordering elements.
/// - Returns: `true` if this sequence precedes `other` in a dictionary
/// ordering as ordered by `comparator`; otherwise, `false`.
public func lexicographicallyPrecedes(_ other: some Sequence<Element>, using comparator: some SortComparator<Element>) -> Bool {
return self.lexicographicallyPrecedes(other) {
comparator.compare($0, $1) == .orderedAscending
}
}
}