Swift 4:如何用Filter替代嵌套循环筛选两个对象数组?
用Swift的Filter替代嵌套循环检查属性相等
嗨,我来帮你搞定这个问题!首先先明确咱们的需求:从server数组里筛选出在local数组中存在相同id,但content已经不一样的Message对象,对吧?
先看看原来用嵌套for循环的写法(模拟你可能会写的代码):
var updatedMessages: [Message] = [] for serverMsg in server { for localMsg in local { if serverMsg.id == localMsg.id && serverMsg.content != localMsg.content { updatedMessages.append(serverMsg) break // 找到匹配的就跳出内层循环,不用继续找了 } } }
接下来咱们把它改成用filter的实现,分两种场景给你说明:
场景1:追求性能(推荐,数据量大时更友好)
先把local数组转成一个以id为key、content为value的字典,这样后续查找的效率会大幅提升:
// 先把local的id和content映射成字典,O(n)时间复杂度 let localContentMap = Dictionary(uniqueKeysWithValues: local.map { ($0.id, $0.content) }) // 用filter筛选server数组 let updatedMessages = server.filter { serverMsg in // 先判断local里有没有这个id的消息 guard let localContent = localContentMap[serverMsg.id] else { return false // local里没有的话,不算更新的消息 } // 对比内容是否不同,不同的话就保留这个server消息 return serverMsg.content != localContent }
这个写法的好处:
- 完全避免了嵌套循环,代码更简洁,意图更明确
- 字典查找是O(1)的时间复杂度,整体时间复杂度从嵌套循环的O(n*m)降到了O(n+m),数组元素多的时候性能提升很明显
场景2:代码极简(数据量小时适用)
如果你的数组元素不多,也可以直接在filter里嵌套contains高阶函数,写法更紧凑:
let updatedMessages = server.filter { serverMsg in local.contains { localMsg in localMsg.id == serverMsg.id && localMsg.content != serverMsg.content } }
这个写法虽然看起来也是“嵌套”,但用声明式的高阶函数替代了手动写循环,代码可读性更强,直接表达了“筛选出server中存在于local里id相同但内容不同的元素”这个意图。
内容的提问来源于stack exchange,提问作者Wych
相关产品推荐
相关产品推荐

