C#中列表元素合并与GROUP_ID覆盖问题的正确实现问询
C# 解决分组时GROUP_ID被覆盖的问题
原始数据
| ID | ENTITY_NAME | ENTITY_VALUE | SECTION_GROUP | DOC_ID | GROUP_ID |
|---|---|---|---|---|---|
| 1 | dNumber | U220059090 | GROUP 1 | 40 | 0 |
| 2 | tDate | 6-Dec-22 | GROUP 1 | 40 | 0 |
| 3 | dNumber | U220059090 | GROUP 2 | 40 | 0 |
| 4 | tDate | 6-Dec-22 | GROUP 2 | 40 | 0 |
| 5 | sCompany | bp | 40 | 0 |
需求
将SECTION_GROUP为空的条目合并到每个SECTION_GROUP分组结果中,同时为每个分组设置递增的GROUP_ID,期望输出如下:
ENTITY_NAME ENTITY_VALUE SECTION_GROUP DOC_ID GROUP_ID dNumber U220059090 GROUP 1 40 1 tDate 6-Dec-22 GROUP 1 40 1 sCompany bp 40 1 dNumber U220059090 GROUP 2 40 2 tDate 6-Dec-22 GROUP 2 40 2 sCompany bp 40 2
当前实现代码
var itemSectionGroup = item.Where(x => !string.IsNullOrEmpty(x.Sectiongroup)); var itemSectionGroupNull = item.Where(x => string.IsNullOrEmpty(x.Sectiongroup)).ToList(); var group = itemSectionGroup.GroupBy(x => new { x.Sectiongroup }); int grp_num = 1; foreach (var grp in group) { List<ParserRequestEntityLog> newList = itemSectionGroupNull.GetRange(0,itemSectionGroupNull.Count); grp.ToList().ForEach(x => x.Groupid = grp_num); newList.ToList().ForEach(x => x.Groupid = grp_num); resultList.AddRange(grp.ToList()); resultList.AddRange(newList); grp_num += 1; }
错误结果
由于ParserRequestEntityLog是引用类型,每次循环修改的都是同一个对象实例的Groupid,导致之前设置的GROUP_ID被后续循环覆盖,错误输出如下:
ENTITY_NAME ENTITY_VALUE SECTION_GROUP DOC_ID GROUP_ID dNumber U220059090 GROUP 1 40 1 tDate 6-Dec-22 GROUP 1 40 1 sCompany bp 40 2 <= this is getting overridden. dNumber U220059090 GROUP 2 40 2 tDate 6-Dec-22 GROUP 2 40 2 sCompany bp 40 2
正确实现方法
核心解决思路:为每个分组创建空SECTION_GROUP条目的副本,而不是复用同一个对象实例。
方法1:实现对象克隆
先给ParserRequestEntityLog添加克隆方法,创建新实例:
public class ParserRequestEntityLog { // 原有属性 public string Sectiongroup { get; set; } public int Groupid { get; set; } public string ENTITY_NAME { get; set; } public string ENTITY_VALUE { get; set; } public int DOC_ID { get; set; } // 克隆方法,创建新实例并复制属性 public ParserRequestEntityLog Clone() { return new ParserRequestEntityLog { Sectiongroup = this.Sectiongroup, Groupid = this.Groupid, ENTITY_NAME = this.ENTITY_NAME, ENTITY_VALUE = this.ENTITY_VALUE, DOC_ID = this.DOC_ID }; } }
修改循环逻辑,使用克隆后的对象:
var itemSectionGroup = item.Where(x => !string.IsNullOrEmpty(x.Sectiongroup)); var itemSectionGroupNull = item.Where(x => string.IsNullOrEmpty(x.Sectiongroup)).ToList(); var groups = itemSectionGroup.GroupBy(x => x.Sectiongroup); int grpNum = 1; foreach (var grp in groups) { // 为当前分组创建空条目副本 var nullItemCopies = itemSectionGroupNull.Select(x => { var copy = x.Clone(); copy.Groupid = grpNum; return copy; }).ToList(); // 设置当前分组条目的GROUP_ID foreach (var itemInGroup in grp) { itemInGroup.Groupid = grpNum; } // 添加到结果 resultList.AddRange(grp); resultList.AddRange(nullItemCopies); grpNum++; }
方法2:直接在LINQ中创建新实例(无需克隆方法)
如果不想修改实体类,可以直接在循环中创建新实例并复制属性:
var itemSectionGroup = item.Where(x => !string.IsNullOrEmpty(x.Sectiongroup)); var itemSectionGroupNull = item.Where(x => string.IsNullOrEmpty(x.Sectiongroup)).ToList(); var groups = itemSectionGroup.GroupBy(x => x.Sectiongroup); int grpNum = 1; foreach (var grp in groups) { // 复制空条目并设置GROUP_ID var nullItemCopies = itemSectionGroupNull.Select(x => new ParserRequestEntityLog { Sectiongroup = x.Sectiongroup, Groupid = grpNum, ENTITY_NAME = x.ENTITY_NAME, ENTITY_VALUE = x.ENTITY_VALUE, DOC_ID = x.DOC_ID }).ToList(); // 设置分组内条目的GROUP_ID grp.ToList().ForEach(x => x.Groupid = grpNum); resultList.AddRange(grp); resultList.AddRange(nullItemCopies); grpNum++; }
方法3:更简洁的LINQ链式写法
如果追求代码简洁,可以用LINQ一次性生成结果:
var nonNullGroups = item.Where(x => !string.IsNullOrEmpty(x.Sectiongroup)) .GroupBy(x => x.Sectiongroup) .Select((grp, index) => new { GroupId = index + 1, Items = grp.Select(x => { x.Groupid = index + 1; return x; }).ToList() }); var nullItems = item.Where(x => string.IsNullOrEmpty(x.Sectiongroup)).ToList(); var resultList = nonNullGroups.SelectMany(g => g.Items.Concat(nullItems.Select(n => { var copy = new ParserRequestEntityLog { Sectiongroup = n.Sectiongroup, Groupid = g.GroupId, ENTITY_NAME = n.ENTITY_NAME, ENTITY_VALUE = n.ENTITY_VALUE, DOC_ID = n.DOC_ID }; return copy; })) ).ToList();
这些方法都能避免引用类型的覆盖问题,因为每个分组的空条目都是独立的新实例,不会被后续循环修改。
内容的提问来源于stack exchange,提问作者tt0206
相关产品推荐
相关产品推荐

