SwiftUI 购物车Drink结构体重复项按数量合并删除实现问题
错误原因排查
- 索引越界:你遍历的是数组初始状态的索引集合,执行
remove(at:)后数组实际长度缩小,但循环仍使用原始索引访问元素,尤其是你直接访问i+1,当i为数组最后一个索引时必然超出有效范围。 - 相邻判断逻辑不成立:你仅对索引按名称排序,没有实际重排
cartDrinks数组的元素顺序,相同名称的饮品并不会相邻,判断cartDrinks[i].name == cartDrinks[i+1].name的逻辑本身无法生效。 - 遍历修改冲突:即使先对数组排序,正序遍历过程中删除元素会导致后续元素的索引全部前移,会出现漏检元素的问题。
正确实现方案
推荐使用字典分组的方案,无索引操作风险,逻辑更稳定:
func mergeItem() { // 按饮品名称对购物车元素分组 let groupedDrinks = Dictionary(grouping: cartDrinks, by: \.name) // 重构合并后的购物车数组 cartDrinks = groupedDrinks.compactMap { group in // 取同组第一个元素作为基准(默认相同名称的饮品其他属性一致) guard var baseDrink = group.value.first else { return nil } // 需求为每个重复条目给基准unit加1,使用如下逻辑 baseDrink.unit += group.value.count - 1 // 如果需要累加所有条目的unit数量,替换为以下代码 // baseDrink.unit = group.value.reduce(0) { $0 + $1.unit } return baseDrink } // 如果需要保留原数组的排序规则,可在此处添加排序逻辑,例如按添加日期排序: // cartDrinks.sort { $0.date < $1.date } }
如果你偏好遍历修改数组的实现方式,可以使用倒序遍历方案,避免索引错位:
func mergeItem() { // 先按名称排序数组,让相同名称的元素相邻 cartDrinks.sort { $0.name < $1.name } // 倒序遍历,删除元素不会影响未遍历的前序索引 var i = cartDrinks.count - 1 while i > 0 { if cartDrinks[i].name == cartDrinks[i-1].name { cartDrinks[i-1].unit += 1 // 如需累加unit,替换为:cartDrinks[i-1].unit += cartDrinks[i].unit cartDrinks.remove(at: i) } i -= 1 } }
内容的提问来源于stack exchange,提问作者Liangn1an
相关产品推荐
相关产品推荐

