Swift中对象数组排序:从简单到复杂

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在Swift中按属性对对象数组排序:深入底层原理



你好,同行!如果你曾经用Swift编写过显示用户列表、商品列表或任务列表的应用程序,那么你肯定遇到过需要对这些数据进行排序的情况。“How to sort an array of custom objects by property value?”这个问题是Stack Overflow上最热门的问题之一。这并非偶然:乍一看似乎很简单,但深入挖掘后,你会发现一系列丰富的可能性。



今天,我们不仅仅给出一个现成的答案。我们将深入探讨Swift底层的排序机制,了解涉及哪些原理,以及如何编写不仅可用,而且高效优雅的代码。开始吧!



什么是Swift中的对象数组排序?



想象一下:你有一个User对象数组。每个用户都有姓名、年龄和评分。你需要将它们按年龄(从小到大)排序后显示在屏幕上。



在Swift中,这可以通过内置方法sort()(原地排序数组)和sorted()(返回新的排序后数组)来实现。两者都接受一个用于确定顺序的闭包。



struct User {    let name: String    let age: Int    let rating: Double}

let users = [ User(name: "安娜", age: 25, rating: 4.5), User(name: "鲍里斯", age: 30, rating: 3.8), User(name: "维卡", age: 22, rating: 4.9)]

// 按年龄排序(升序)let sortedByAge = users.sorted { $0.age < $1.age }print(sortedByAge.map { $0.name }) // ["维卡", "安娜", "鲍里斯"]


就是这样。但让我们深入了解一下这里实际发生了什么。



sort()底层工作原理:算法与闭包



Swift中的sort()方法使用混合算法TimSort(以Tim Peters命名)。这是一种自适应、稳定的排序算法,结合了归并排序和插入排序。它在部分有序的数据上尤其高效——例如新闻推送和任务列表!



你传递的闭包是一个排序谓词:一个接受两个元素并返回true(如果第一个应排在第二个之前)的函数。Swift会多次调用此闭包来比较元素对。



重要提示:如果你的对象符合Comparable协议,甚至可以完全省略闭包:



struct User: Comparable {    let name: String    let age: Int        static func < (lhs: User, rhs: User) -> Bool {        return lhs.age < rhs.age    }}

let sortedUsers = users.sorted() // 现在更简单了


但如果需要在运行时按不同属性排序呢?这时键路径(KeyPath)就派上用场了。



使用KeyPath排序:优雅与灵活



从Swift 4开始,我们有了KeyPath。这是一种安全引用对象属性的方式。将KeyPath与闭包结合,可以编写通用的排序函数:



extension Array {    mutating func sort<T: Comparable>(by keyPath: KeyPath<Element, T>, ascending: Bool = true) {        sort { ascending ?            $0[keyPath: keyPath] < $1[keyPath: keyPath] :            $0[keyPath: keyPath] > $1[keyPath: keyPath]        }    }        func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, ascending: Bool = true) -> [Element] {        return sorted { ascending ?            $0[keyPath: keyPath] < $1[keyPath: keyPath] :            $0[keyPath: keyPath] > $1[keyPath: keyPath]        }    }}

// 使用方式:users.sort(by: \\.age) // 按年龄(升序)let sortedByRating = users.sorted(by: \\.rating, ascending: false) // 按评分(降序)


很优雅吧?类型安全

博客

书籍推荐