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

C#中基于整数数组与属性值维护唯一集合的优化方案

优化整数数组作为唯一标识的对象集合性能方案

问题背景

  • 需求:维护一个对象集合,对象唯一性由整数数组逐值比较判定;若数组内容相同,保留PropertyB属性值最高的对象。
  • 当前实现:采用Dictionary<string, myObject>,以整数数组拼接成的字符串(通过string.Join(",", array)生成)作为键。添加对象时,若键已存在,当新对象PropertyB值更大时替换原有对象。
  • 性能瓶颈:大数据量场景下,string.Join操作的字符串拼接耗时严重,成为性能短板。

当前实现代码(含已知错误)

private readonly Dictionary<string, myObject> myHashLookup = new Dictionary<(string,int), myObject>(); // 注:此处存在类型声明不匹配错误,实际应为Dictionary<string, myObject>

public void Add(myObject t)
{
    string id = t.GetId(); // 内部实现为string.Join(",", myIntArray)
    myObject cur_object;
    myHashLookup.TryGetValue(id, out cur_object);            
    if (cur_object == null || (t.PropertyB > cur_object.PropertyB))
        myHashLookup[id)] = t; // 注:此处多了一个右括号,应为myHashLookup[id] = t;
}

优化方案

方案1:自定义整数数组相等比较器(通用场景)

直接以整数数组作为Dictionary的键,通过自定义IEqualityComparer<int[]>实现数组的逐值相等判断与哈希码计算,完全避免字符串拼接操作。

自定义比较器实现

public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
    public bool Equals(int[] x, int[] y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        if (x.Length != y.Length) return false;
        
        // 逐元素比较
        for (int i = 0; i < x.Length; i++)
        {
            if (x[i] != y[i]) return false;
        }
        return true;
    }

    public int GetHashCode(int[] obj)
    {
        if (obj == null) return 0;
        
        // 基于数组元素计算哈希码,采用经典的哈希组合方式
        int hash = 17;
        foreach (int num in obj)
        {
            hash = hash * 31 + num.GetHashCode();
        }
        return hash;
    }
}

修改后的集合与Add方法

// 使用自定义比较器初始化Dictionary
private readonly Dictionary<int[], myObject> myHashLookup = new Dictionary<int[], myObject>(new IntArrayEqualityComparer());

public void Add(myObject t)
{
    int[] key = t.myIntArray; // 直接使用对象的整数数组作为键
    if (myHashLookup.TryGetValue(key, out var curObject))
    {
        // 仅当新对象PropertyB更大时替换
        if (t.PropertyB > curObject.PropertyB)
        {
            myHashLookup[key] = t;
        }
    }
    else
    {
        myHashLookup.Add(key, t);
    }
}

方案2:固定长度数组用结构体包装(特殊场景)

如果整数数组的长度固定,可以定义结构体持有数组元素,利用结构体的默认值比较特性,无需自定义比较器即可作为Dictionary的键,性能更优。

示例(数组长度固定为3)

// 定义结构体作为键
public struct FixedArrayKey
{
    public int Item1 { get; }
    public int Item2 { get; }
    public int Item3 { get; }

    public FixedArrayKey(int[] array)
    {
        if (array.Length != 3)
            throw new ArgumentException("数组长度必须为3");
            
        Item1 = array[0];
        Item2 = array[1];
        Item3 = array[2];
    }
}

修改后的集合与Add方法

private readonly Dictionary<FixedArrayKey, myObject> myHashLookup = new Dictionary<FixedArrayKey, myObject>();

public void Add(myObject t)
{
    var key = new FixedArrayKey(t.myIntArray);
    if (myHashLookup.TryGetValue(key, out var curObject))
    {
        if (t.PropertyB > curObject.PropertyB)
        {
            myHashLookup[key] = t;
        }
    }
    else
    {
        myHashLookup.Add(key, t);
    }
}

方案对比

  • 方案1:适配任意长度的整数数组,无需修改对象结构,性能比字符串拼接提升显著,是通用场景的最优选择。
  • 方案2:仅适用于固定长度数组,结构体的哈希码与相等比较由编译器自动生成,性能略高于方案1,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 14:54:21