Swift中如何按AccountNumber合并NSArray与NSMutableArray的字典数组?
解决NSMutableArray与NSArray基于AccountNumber的合并问题
我看了你写的合并数组的代码,发现几个关键问题导致功能不符合预期:
- 重复添加元素:内层循环里只要不匹配就执行
logOrderMutArray.add(openOrderArray[j]),这会让同一个openOrder元素被重复添加N次(N等于logOrderMutArray的元素数量),完全不是你想要的结果。 - 替换逻辑错误:你把openOrder的元素放到了
editDict["newlyAdded"]这个键下,而不是直接用openOrder的元素替换原数组中的对应元素,根本没实现“替换匹配元素”的需求。 - 类型处理不安全:大量使用
as!强制解包,很容易因为数据格式问题崩溃,而且依赖Objective-C的集合类(NSDictionary/NSMutableArray)不如用Swift原生集合更简洁安全。
正确的实现思路
我们可以用字典做快速映射来优化逻辑,把时间复杂度从嵌套循环的O(n*m)降到O(n+m),同时避免重复添加:
- 先把
openOrderArray转换成以AccountNumber为key的字典,方便快速查找对应元素。 - 遍历
logOrderMutArray,检查每个元素的AccountNumber是否在字典中存在:存在就用openOrder的元素替换,不存在就保留原元素。 - 最后把openOrder中所有没在logOrder里出现过的元素,添加到
logOrderMutArray中。
推荐的Swift原生实现代码
这种写法更符合Swift的语言习惯,类型安全且逻辑清晰:
func mergeOrderAndOpenOrderArrayData() { // 将NSArray转为Swift原生数组,方便后续处理 guard let openOrders = openOrderArray as? [[String: Any]] else { return } // 构建AccountNumber到订单的映射字典,过滤掉没有AccountNumber的无效元素 let openOrderDict = Dictionary(uniqueKeysWithValues: openOrders.compactMap { order in guard let accountNum = order["AccountNumber"] as? String else { return nil } return (accountNum, order) }) // 处理原日志订单数组:替换匹配的元素 guard var logOrders = logOrderMutArray as? [[String: Any]] else { return } logOrders = logOrders.map { logOrder in guard let accountNum = logOrder["AccountNumber"] as? String, let matchedOpenOrder = openOrderDict[accountNum] else { return logOrder } // 直接返回openOrder的元素完成替换 return matchedOpenOrder } // 找出openOrder中未在logOrder里出现的元素 let logAccountNumbers = Set(logOrders.compactMap { $0["AccountNumber"] as? String }) let newOrdersToAdd = openOrders.filter { order in guard let accountNum = order["AccountNumber"] as? String else { return false } return !logAccountNumbers.contains(accountNum) } // 更新原NSMutableArray logOrderMutArray.removeAllObjects() logOrderMutArray.addObjects(from: logOrders + newOrdersToAdd) }
保留Objective-C风格的实现(直接操作NSMutableArray)
如果你更习惯用Objective-C的集合类,也可以这样写:
func mergeOrderAndOpenOrderArrayData() { // 构建openOrder的AccountNumber映射字典 let openOrderDict = NSMutableDictionary() for order in openOrderArray { guard let accountNum = (order as AnyObject).value(forKey: "AccountNumber") as? String else { continue } openOrderDict[accountNum] = order } // 遍历原数组,替换匹配的元素,同时移除字典中已匹配的项 for i in 0..<logOrderMutArray.count { let logOrder = logOrderMutArray[i] guard let accountNum = (logOrder as AnyObject).value(forKey: "AccountNumber") as? String, let matchedOpenOrder = openOrderDict[accountNum] else { continue } logOrderMutArray.replaceObject(at: i, with: matchedOpenOrder) openOrderDict.removeObject(forKey: accountNum) } // 添加剩余未匹配的openOrder元素 logOrderMutArray.addObjects(from: openOrderDict.allValues) }
这两种写法都能实现你的需求:匹配到相同AccountNumber的元素就替换,未匹配的就添加,而且不会出现重复添加的问题,同时处理了可选值避免崩溃。
内容的提问来源于stack exchange,提问作者B.Saravana Kumar
相关产品推荐
相关产品推荐

