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

使用HashSet实现厂商去重及数量累加的问题求助

问题描述

我有一个格式为(Id、ProductId、Title、Quantity、Manufacturer)的items列表,具体数据如下:

IdProductIdTitleQuantityManufacturer
110蓝光播放器3Sony
220CD播放器2Sony
330冰箱1LG
440洗衣机1Samsung

我希望按厂商分组返回厂商ID、厂商名称、总数量的汇总数据,预期结果如下:

Manufacturer IdManufacturer NameQuantity
1234Sony5
1235LG1
1236Samsung1

我编写了如下GetManufacturerData方法:

public void GetManufacturerData()
{
     var manData = new HashSet<ManufacturerAndQuantity>();

        foreach (var item in items)
        {
            var mq = new ManufacturerAndQuantity();
            var manufac = myService.GetManufacturer(item.ProductId); 
            mq.Title = manufac.Title;
            mq.Id = manufac.Id;
            mq.Total += item.Quantity;

            if (!manData.Equals(c))
            {
                manData.Add(c);
            }
        }
}

对应的ManufacturerAndQuantity类实现了IEquatable<ManufacturerAndQuantity>接口:

public class ManufacturerAndQuantity : IEquatable<ManufacturerAndQuantity>
{
    public int? Id { get; set; }
    public string Title { get; set; }
    public int Total{ get; set; } 

    public bool Equals(ManufacturerAndQuantity? other)
    {
        return this.Id.Equals(other.Id);
    }
}

原本认为HashSet会自动过滤重复项,但目前它仍会添加相同厂商的条目(如Sony被添加两次),且未正确累加总数量。请问我的代码哪里存在问题?

补充说明:只能通过ProductId调用外部服务获取厂商信息,两者无直接关联。


问题分析与修复

1. 变量引用错误

代码中出现未定义变量c,原本应该引用刚创建的mq对象,这会直接导致逻辑错误——你根本没把当前处理的厂商条目和HashSet做有效性对比。

2. HashSet存在性判断逻辑错误

你调用manData.Equals(c)是把整个HashSet对象和变量比较,而非检查HashSet中是否包含该厂商条目。正确做法是用manData.Contains(mq)判断是否已存在相同厂商的记录。

3. 未实现已有厂商的数量累加

即使HashSet能识别重复项,你也没有对已存在的厂商条目进行数量累加,而是每次都创建新对象,直接导致同厂商条目重复添加。

4. 未重写GetHashCode方法

实现IEquatable<T>接口时必须同时重写GetHashCode,HashSet依赖哈希码快速定位元素。只重写Equals不重写GetHashCode,会导致HashSet认为两个Id相同的对象是不同的(默认哈希码基于对象引用)。


修复后的代码

修正ManufacturerAndQuantity类

public class ManufacturerAndQuantity : IEquatable<ManufacturerAndQuantity>
{
    public int? Id { get; set; }
    public string Title { get; set; }
    public int Total { get; set; } 

    public bool Equals(ManufacturerAndQuantity? other)
    {
        if (other == null) return false;
        // 处理Id为null的情况,避免空引用异常
        return Id.HasValue && other.Id.HasValue && Id.Value.Equals(other.Id.Value);
    }

    // 必须重写GetHashCode,基于判断相等的核心字段(Id)
    public override int GetHashCode()
    {
        return Id.HasValue ? Id.Value.GetHashCode() : 0;
    }

    // 重写Object.Equals保持逻辑一致性
    public override bool Equals(object? obj)
    {
        return Equals(obj as ManufacturerAndQuantity);
    }
}

修正GetManufacturerData方法

public void GetManufacturerData()
{
    var manData = new HashSet<ManufacturerAndQuantity>();

    foreach (var item in items)
    {
        var manufac = myService.GetManufacturer(item.ProductId);
        // 先检查HashSet中是否已有该厂商的条目
        var existingMq = manData.FirstOrDefault(mq => mq.Id == manufac.Id);
        
        if (existingMq != null)
        {
            // 已有条目,累加数量
            existingMq.Total += item.Quantity;
        }
        else
        {
            // 无对应条目,创建新对象并添加
            var mq = new ManufacturerAndQuantity
            {
                Id = manufac.Id,
                Title = manufac.Title,
                Total = item.Quantity
            };
            manData.Add(mq);
        }
    }
}

额外优化建议

可以先对items按ProductId分组,减少外部服务调用次数:

// 按ProductId分组,避免重复调用GetManufacturer
var groupedItems = items.GroupBy(i => i.ProductId);
foreach (var group in groupedItems)
{
    var manufac = myService.GetManufacturer(group.Key);
    var totalQuantity = group.Sum(i => i.Quantity);
    
    var existingMq = manData.FirstOrDefault(mq => mq.Id == manufac.Id);
    if (existingMq != null)
    {
        existingMq.Total += totalQuantity;
    }
    else
    {
        manData.Add(new ManufacturerAndQuantity
        {
            Id = manufac.Id,
            Title = manufac.Title,
            Total = totalQuantity
        });
    }
}

内容的提问来源于stack exchange,提问作者KeithViking

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:19:56