Generic function to sort array of class by properties

前端 未结 3 741
我在风中等你
我在风中等你 2020-12-02 01:15

I want to create a generic function to sort an array of classes based on a property passed.

For example, I have these classes

public class Car {
             


        
相关标签:
3条回答
  • 2020-12-02 01:18

    Here you go:

    extension Array {
        mutating func propertySort<T: Comparable>(_ property: (Element) -> T) {
            sort(by: { property($0) < property($1) })
        }
    }
    

    Usage:

    persons.propertySort({$0.name})
    

    And here is a non-mutating version:

    func propertySorted<T: Comparable>(_ property: (Element) -> T) -> [Element] {
        return sorted(by: {property($0) < property($1)})
    }
    

    As Leo Dabus pointed out, you can generalise the extension to any MutableCollection that is also a RandomAccessCollection:

    extension MutableCollection where Self : RandomAccessCollection {
        ...
    
    0 讨论(0)
  • 2020-12-02 01:30

    Expanding on @MartinR answer to allow increasing (<) or decreasing (>) sort:


    extension MutableCollection where Self: RandomAccessCollection {
        mutating func sort<T: Comparable>(_ keyPath: KeyPath<Element, T>, by areInIncreasingOrder: ((T, T) -> Bool) = (<)) {
            sort(by: { areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
        }
    }
    

    extension Sequence {
        func sorted<T: Comparable>(_ keyPath: KeyPath<Element, T>, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element] {
            sorted(by: { areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
        }
    }
    

    people.sorted(\.age)
    people.sorted(\.age, by: >)
    
    cars.sorted(\.manufacturer)
    cars.sorted(\.manufacturer, by: >)
    

    edit/update:

    To suport sorting a custom object by an optional property that conforms to Comparable protocol:


    extension MutableCollection where Self: RandomAccessCollection {
        mutating func sort<T: Comparable>(_ keyPath: KeyPath<Element, Optional<T>>, by areInIncreasingOrder: ((T, T) -> Bool) = (<)) {
            sort(by: {
                switch ($0[keyPath: keyPath], $1[keyPath: keyPath]) {
                case let (lhs?, rhs?): return areInIncreasingOrder(lhs, rhs)
                case (.none, _): return false
                case (_, .none): return true
                }
            })
        }
    }
    

    extension Sequence {
        func sorted<T: Comparable>(_ keyPath: KeyPath<Element, Optional<T>>, by areInIncreasingOrder: ((T,T)-> Bool) = (<)) -> [Element]  {
            sorted(by: {
                switch ($0[keyPath: keyPath], $1[keyPath: keyPath]) {
                case let (lhs?, rhs?): return areInIncreasingOrder(lhs, rhs)
                case (.none, _): return false
                case (_, .none): return true
                }
            })
        }
    }
    

    Usage:

    array.sort(\.optionalStringProperty) {
        $0.localizedStandardCompare($1) == .orderedAscending
    }
    print(array)
    
    0 讨论(0)
  • 2020-12-02 01:42

    Starting with Swift 4 you can define a sorting method which takes a Key-Path Expression as argument. As Leo points out, these methods can be defined more generally as protocols extension methods (for mutable collections and sequences, respectively):

    extension MutableCollection where Self: RandomAccessCollection {
        // Mutating in-place sort:
        mutating func sort<T: Comparable>(byKeyPath keyPath: KeyPath<Element, T>) {
            sort(by: { $0[keyPath: keyPath] < $1[keyPath: keyPath] })
        }
    }
    
    extension Sequence {
        // Non-mutating sort, returning a new array:
        func sorted<T: Comparable>(byKeyPath keyPath: KeyPath<Element, T>) -> [Element] {
            return sorted(by: { $0[keyPath: keyPath] < $1[keyPath: keyPath] })
        }
    }
    

    Example usage:

    persons.sort(byKeyPath: \.name)
    cars.sort(byKeyPath: \.manufacturer)
    

    For more information about key-path expressions, see SE-0161 Smart KeyPaths: Better Key-Value Coding for Swift.

    0 讨论(0)
提交回复
热议问题