C#合并含重复项的两个列表:按规则筛选保留元素
问题描述
现有两个包含对象的列表,每个对象具备Role、Interest、Declaration、CreatedOn四个属性。当多个对象的Role和Interest属性值完全相同时,判定为重复项,需按以下规则保留唯一对象:
- 若重复项中存在
Declaration为"Yes"或"No"的对象,保留其中CreatedOn最早的; - 若重复项仅包含
Declaration为"Calculated"的对象,同样保留其中CreatedOn最早的(Yes/No优先级高于Calculated)。
已通过concatList = list1.Concat(list2)合并两个列表,但现有实现存在嵌套foreach循环效率低下、无法正确处理全Calculated分组的问题,需要优化逻辑并实现正确的重复项筛选。
现有问题代码:
var concatList = list1.Concat(list2); var listAfterMerge = new List<object>(); foreach (var item in concatList ) { var duplicates = concatList.Where(x => x.Role == item.Role && x.Interest == item.Interest); if (duplicates .Count() > 1) { foreach (var duplicate in duplicates .OrderByDescending(x => x.CreatedOn)) { if(duplicate.Declaration.Value == "Yes" || duplicate.Declaration.Value == "No") { listAfterMerge.Add(duplicate); break; } else { ...? } } } else { listAfterMerge.Add(item); } }
优化后的解决方案
利用Linq的GroupBy方法可以高效实现分组筛选,避免嵌套循环的性能问题,同时精准处理所有规则场景:
实现代码
// 假设你的对象类型为UserDeclaration,替换为你实际的类型 var concatList = list1.Concat(list2); var listAfterMerge = concatList // 按Role和Interest分组,把重复项归为一组 .GroupBy(x => new { x.Role, x.Interest }) .Select(group => { // 先筛选出优先级高的Yes/No项 var priorityItems = group.Where(item => item.Declaration == "Yes" || item.Declaration == "No"); // 如果有优先级项,取CreatedOn最早的;否则取全组最早的 return priorityItems.Any() ? priorityItems.OrderBy(item => item.CreatedOn).First() : group.OrderBy(item => item.CreatedOn).First(); }) .ToList();
逻辑说明
- 分组去重:通过
GroupBy将具有相同Role和Interest的对象归为一组,一次遍历即可完成分组,比嵌套循环重复查询效率高得多; - 优先级筛选:对每个分组先提取
Declaration为Yes/No的高优先级子集; - 最终选择:如果高优先级子集不为空,就取其中
CreatedOn最早的对象;如果全组都是Calculated,则直接取整个分组中CreatedOn最早的对象; - 结果收集:将所有分组筛选出的唯一对象收集为最终列表,自动保证无
Role+Interest重复的对象。
注意事项
- 代码中假设对象类型为
UserDeclaration,请替换为你实际使用的类型(不要用object,强类型更安全且避免反射/类型转换问题); - 如果
Declaration是可空类型(比如string?),需要在筛选时额外处理空值场景(例如添加item.Declaration != null的判断)。
内容的提问来源于stack exchange,提问作者Leth
相关产品推荐
相关产品推荐

