You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中列表元素合并与GROUP_ID覆盖问题的正确实现问询

C# 解决分组时GROUP_ID被覆盖的问题

原始数据

IDENTITY_NAMEENTITY_VALUESECTION_GROUPDOC_IDGROUP_ID
1dNumberU220059090GROUP 1400
2tDate6-Dec-22GROUP 1400
3dNumberU220059090GROUP 2400
4tDate6-Dec-22GROUP 2400
5sCompanybp400

需求

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 02:20:31