如何按ID匹配过滤两个结构体数组并关联指定属性信息?
按ID匹配关联用户与文章数组的最优实现方式
需求背景
现有两个结构体定义:
struct User { let id: Int let name: String var arts: [Article]? } struct Article { let userId: Int let id: Int let title: String let body: String }
需将[User]数组与[Article]数组按User.id == Article.userId的规则关联,把每个用户对应的所有文章赋值到其arts属性中。
原始实现及问题
用户最初的实现代码:
var articles = [Article]() var users = [User]() self?.articles.forEach({ article in guard let userIndex = self?.users.firstIndex(where: { $0.id == article.userId }) else { print("Failed to find a User by UserID") return } self?.users[userIndex].arts?.append(article) })
该实现的核心问题是时间复杂度高:每遍历一篇文章都要遍历整个用户数组查找匹配项,整体复杂度为O(n*m),当数据量较大时性能会明显下降;同时可选值的append操作存在空值风险,代码可读性也较差。
最优实现方案
通过字典分组预处理文章数组,将查找操作的时间复杂度降为O(1),整体复杂度优化为O(n + m),代码更简洁可靠。
方案1:生成新的用户数组(推荐,避免原数组修改副作用)
// 1. 按userId将文章分组,构建映射字典 let articlesByUserId = Dictionary(grouping: articles, by: { $0.userId }) // 2. 遍历用户数组,匹配对应文章 let updatedUsers = users.map { user in var mutableUser = user // 直接赋值对应文章数组,无则赋值空数组 mutableUser.arts = articlesByUserId[user.id] ?? [] return mutableUser }
方案2:直接修改原用户数组
如果需要直接修改原数组而非生成新数组,可使用索引遍历:
let articlesByUserId = Dictionary(grouping: articles, by: { $0.userId }) for index in users.indices { users[index].arts = articlesByUserId[users[index].id] ?? [] }
方案优势
- 性能大幅提升:预分组仅需遍历一次文章数组,后续用户匹配为O(1)查找,数据量大时优势明显
- 代码简洁安全:避免嵌套遍历和索引操作,同时处理了
arts的空值情况,无需额外的可选值判断 - 可读性更强:逻辑清晰,通过字典映射直接关联用户与文章,意图明确
内容的提问来源于stack exchange,提问作者Josué H.
相关产品推荐
相关产品推荐

