如何使用LINQ按ComboUniqueId获取唯一ComboAmount并计算总和
问题分析与修复方案
先梳理下你代码里的几个核心问题,然后给你修正后的实现:
你当前代码的主要问题
Distinct用法错误:Linq的Distinct默认是对比整个匿名对象的所有属性,没有直接接受“按指定字段去重”的重载。你需要用DistinctBy(.NET Core 3.0+、.NET 5及以上支持)或者GroupBy来实现按ComboUniqueId去重。- 索引不匹配问题:循环里用
this.OrderDetailArr[i]去取附加项是错误的——ListUnique是去重后的集合,它的索引和原数组完全没有对应关系,应该直接用去重后对象的ItemAddOnsArr。 - 套餐金额逻辑不符合预期:原代码里当
ComboId != null时直接把FinalTotal赋值为ComboAmount,这会覆盖之前累加的所有总和,显然不是你想要的计算逻辑。
修正后的代码(推荐用DistinctBy,简洁高效)
decimal FinalTotal = 0; // 按ComboUniqueId去重,拿到每个唯一套餐的相关数据 var uniqueCombos = this.OrderDetailArr .DistinctBy(x => x.ComboUniqueId) .Select(x => new { x.ComboAmount, x.ComboId, x.ItemAddOnsArr, x.TotalPrice }); foreach (var combo in uniqueCombos) { // 先累加当前项的基础总价 FinalTotal += combo.TotalPrice; // 如果是套餐,用套餐金额替换当前项的基础总价(如果是累加逻辑就改成+=) if (combo.ComboId != null) { FinalTotal -= combo.TotalPrice; // 先减去之前加的基础价 FinalTotal += combo.ComboAmount; // 再加上套餐价 } // 累加当前项的附加项总价 if (combo.ItemAddOnsArr != null) { foreach (var addOn in combo.ItemAddOnsArr) { FinalTotal += addOn.AddOnTotalPrice; } } }
如果你用的是旧版.NET(不支持DistinctBy),用GroupBy替代
decimal FinalTotal = 0; // 按ComboUniqueId分组,取每组第一个元素作为唯一代表 var uniqueCombos = this.OrderDetailArr .GroupBy(x => x.ComboUniqueId) .Select(g => g.First()) .Select(x => new { x.ComboAmount, x.ComboId, x.ItemAddOnsArr, x.TotalPrice }); // 后续循环逻辑和上面完全一致 foreach (var combo in uniqueCombos) { FinalTotal += combo.TotalPrice; if (combo.ComboId != null) { FinalTotal -= combo.TotalPrice; FinalTotal += combo.ComboAmount; } if (combo.ItemAddOnsArr != null) { foreach (var addOn in combo.ItemAddOnsArr) { FinalTotal += addOn.AddOnTotalPrice; } } }
关键改进点说明
- 正确实现按
ComboUniqueId去重:用DistinctBy直接指定去重的键,或者GroupBy分组后取每组第一个元素,确保每个唯一的ComboUniqueId只保留一条数据。 - 避免索引混乱:用
foreach遍历去重后的集合,直接操作当前套餐对象的属性,彻底解决原代码中索引不匹配的问题。 - 修正套餐金额计算逻辑:把“直接覆盖总和”改成“替换当前项的基础价为套餐价”,更符合常规的套餐计价逻辑(如果你的需求是累加套餐金额,直接把这两行改成
FinalTotal += combo.ComboAmount即可)。 - 附加项匹配正确:直接遍历当前套餐的
ItemAddOnsArr,确保附加项和对应的套餐一一对应。
内容的提问来源于stack exchange,提问作者Addi
相关产品推荐
相关产品推荐

