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

如何在含数组属性的C# Look类数组中查找重复项?

查找包含数组属性的Look类重复项

因为数组是引用类型,默认的相等比较会检查引用地址而非内容,所以直接用匿名类型分组无法正确识别ClothesIds内容相同的重复项。下面提供几种可行的解决方案:

方案一:将数组转换为可哈希的字符串(简单场景首选)

把ClothesIds数组拼接成有序字符串(排序是为了让元素相同但顺序不同的数组被视为相等,若需要严格顺序相同则去掉排序),作为分组键的一部分:

var duplicateLooks = looks.GroupBy(x => new 
{
    x.HairId,
    x.MakeupId,
    ClothesKey = string.Join(",", x.ClothesIds?.OrderBy(id => id) ?? Array.Empty<int>())
})
.Where(g => g.Count() > 1)
.Select(g => g.Key);

注意:如果数组元素包含分隔符(比如逗号),需要换用不会冲突的分隔符,或者对元素进行转义处理。

方案二:自定义相等比较器(无需修改原类)

实现IEqualityComparer<Look>,自定义属性和数组的比较逻辑,然后传给GroupBy的重载方法:

自定义比较器类

public class LookEqualityComparer : IEqualityComparer<Look>
{
    public bool Equals(Look x, Look y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x is null || y is null) return false;

        // 比较基础属性
        if (x.HairId != y.HairId || x.MakeupId != y.MakeupId)
            return false;

        // 比较数组内容
        if (x.ClothesIds == null && y.ClothesIds == null)
            return true;
        if (x.ClothesIds == null || y.ClothesIds == null)
            return false;
        if (x.ClothesIds.Length != y.ClothesIds.Length)
            return false;

        // 选择1:顺序相关的数组比较(严格按元素顺序判断相等)
        for (int i = 0; i < x.ClothesIds.Length; i++)
        {
            if (x.ClothesIds[i] != y.ClothesIds[i])
                return false;
        }

        // 选择2:顺序无关的数组比较(只要元素相同就视为相等)
        // return new HashSet<int>(x.ClothesIds).SetEquals(y.ClothesIds);

        return true;
    }

    public int GetHashCode(Look obj)
    {
        if (obj is null) return 0;

        int hash = HashCode.Combine(obj.HairId, obj.MakeupId);

        if (obj.ClothesIds != null)
        {
            // 对应顺序相关的哈希计算
            foreach (int id in obj.ClothesIds)
            {
                hash = HashCode.Combine(hash, id);
            }

            // 对应顺序无关的哈希计算,替换上面的循环
            // var sortedIds = obj.ClothesIds.OrderBy(id => id);
            // foreach (int id in sortedIds)
            // {
            //     hash = HashCode.Combine(hash, id);
            // }
        }

        return hash;
    }
}

使用比较器分组

var duplicateLooks = looks.GroupBy(look => look, new LookEqualityComparer())
.Where(g => g.Count() > 1)
.Select(g => g.Key);

方案三:让Look类实现IEquatable接口(规范方案)

如果可以修改原Look类,直接实现IEquatable<Look>接口,让类自带正确的相等比较逻辑:

public class Look : IEquatable<Look>
{
    public int HairId { get; set; }
    public int MakeupId { get; set; }
    public int[] ClothesIds { get; set; }

    public bool Equals(Look other)
    {
        if (other is null) return false;
        if (ReferenceEquals(this, other)) return true;

        if (HairId != other.HairId || MakeupId != other.MakeupId)
            return false;

        if (ClothesIds == null && other.ClothesIds == null)
            return true;
        if (ClothesIds == null || other.ClothesIds == null)
            return false;
        if (ClothesIds.Length != other.ClothesIds.Length)
            return false;

        // 顺序相关的比较
        for (int i = 0; i < ClothesIds.Length; i++)
        {
            if (ClothesIds[i] != other.ClothesIds[i])
                return false;
        }

        // 顺序无关的比较,替换上面的循环
        // return new HashSet<int>(ClothesIds).SetEquals(other.ClothesIds);

        return true;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Look);
    }

    public override int GetHashCode()
    {
        int hash = HashCode.Combine(HairId, MakeupId);

        if (ClothesIds != null)
        {
            // 顺序相关的哈希计算
            foreach (int id in ClothesIds)
            {
                hash = HashCode.Combine(hash, id);
            }

            // 顺序无关的哈希计算,替换上面的循环
            // var sortedIds = ClothesIds.OrderBy(id => id);
            // foreach (int id in sortedIds)
            // {
            //     hash = HashCode.Combine(hash, id);
            // }
        }

        return hash;
    }
}

直接分组

此时可以像原来无数组属性时一样使用GroupBy:

var duplicateLooks = looks.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:01:36