[SOLVED] Generic function to sort array of class or struct by properties in Swift

Issue

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 {
    var id: Int
    var manufacturer: String
    var variant: String

    init(id: Int, manufacturer: String, variant: String) {
        self.id = id
        self.manufacturer = manufacturer
        self.variant = variant
    }
}

enum Gender {
    case male
    case female
}

public class Person {
    var id: Int
    var name: String
    var age: Int
    var gender: Gender

    init(id: Int, name: String, age: Int, gender: Gender) {
        self.id = id
        self.name = name
        self.age = age
        self.gender = gender
    }
}

And these arrays,

let cars = [
    Car(id: 1, manufacturer: "Ford", variant: "Focus"),
    Car(id: 2, manufacturer: "Nissan", variant: "Skyline"),
    Car(id: 3, manufacturer: "Dodge", variant: "Charger"),
    Car(id: 4, manufacturer: "Chevrolet", variant: "Camaro"),
    Car(id: 5, manufacturer: "Ford", variant: "Shelby")
]

let persons = [
    Person(id: 1, name: "Ed Sheeran", age: 26, gender: .male),
    Person(id: 2, name: "Phil Collins", age: 66, gender: .male),
    Person(id: 3, name: "Shakira", age: 40, gender: .female),
    Person(id: 4, name: "Rihanna", age: 25, gender: .female),
    Person(id: 5, name: "Bono", age: 57, gender: .male)
]

How to write a generic extension for the array, to sort it based on the property passed? (eg. persons.sort(name) or cars.sort(manufacturer))

Thanks!

Solution

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 {
    ...

Answered By – Sweeper

Answer Checked By – Katrina (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.