如何提高你的iOS代码性能,减少对数组的搜索
为你的Swift和Objective-C代码优化速度的一个提示
遍历一个数组的时间复杂度是O(n)。听起来可以接受,对吗?我们可能会忽视它对代码性能的影响,当我们在截止日期前有大量的工作要做时,就不会投入更多的精力去思考一个更好的解决方案。但是,一旦使用这种技能成为一种自然的反应,我们可能不知道我们甚至在代码中写了嵌套的for-loop或嵌套的过滤器,这使得时间复杂度增加到O(n²),我们很有可能在以后遭受性能问题。
试着在非顺序的集合类型中搜索,比如Set 和Dictionary ,而不是Array ,因为在Set 和dictionary 中搜索的时间复杂度是 O(1),而在Array 中搜索的时间复杂度是 O(n)。
在这篇文章中,我将告诉你如何用Set 和dictionary 来优化速度。
例子1:集合
在例子1中,有所有会员的数据和铂金会员的ID。我们的目标是通过platinumMemberIDs ,从members ,推导出一个白金会员的数组。
let members: [Member]let platinumMemberIDs:[Int]
在优化之前
filter(_:) 的时间复杂度是O(n),而数组的实例方法contains(_:) 的时间复杂度也是O(n)。
下面的方法是对members 数组进行迭代。在每次迭代中,它在platinumMemberIDs 中搜索,检查platinumMemberIDs 是否包含当前成员的ID。
这种方法的时间复杂度是O(n²)。
var platinumMembers = members.filter { platinumMemberIDs.contains($0.id)}
优化后
由于platinumMemberIDs 的顺序并不重要,我们可以将这些数据保存在非顺序的集合类型Set 。在Set ,搜索的时间复杂度是O(1)。整体时间复杂度降低到O(n)。
let platinumMemberIDSet = Set(platinumMemberIDs)
例2:词典
在例2中,有两组来自不同渠道的用户,我们想找出他们的交集。只要一个用户的电子邮件与另一组中另一个用户的电子邮件相同,我们就假定他们是同一个用户。
let starUsers: [User]let recentUsers: [User]
优化前
最简单的方法是写嵌套for-loops来找出重复的用户,但时间复杂度将是O(n²),不是很理想。
var duplicatedUsers = [User]()
优化后
为了降低时间复杂度,我们可以简单地从recentUsers 数组中创建一个字典,每个用户的电子邮件为键,用户对象为值。
let recentUserMap = Dictionary(uniqueKeysWithValues: recentUsers.map { ($0.email, $0) })
然后我们在starUsers 数组中进行搜索,但是在每次迭代中,我们不需要迭代recentUsers 数组来找出优化后的重复用户。相反,我们直接从recentUserMap ,访问电子邮件与当前明星用户相同的最近用户的用户对象。时间复杂度降低到O(n)。
let duplicatedUsers = starUsers.filter { guard let _ = recentUserMap[$0.email] else { return false } return true}