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

如何对SelectMany后的AzureADUser列表按ObjectId+SourceGroups按需去重?

需求:去除AzureADUser的完全重复实例(保留同ObjectId但不同SourceGroups的实例)

现有类定义

public class GroupMembership
{
        public List<AzureADUser> SourceMembers { get; set; }
}

public class AzureADUser
{
    public Guid ObjectId { get; set; }  
    public List<Guid> SourceGroups { get; set; }
}

执行var source = groupsMemberships.SelectMany(x => x.SourceMembers).ToList();后,结果包含不符合预期的重复实例:我们需要保留同一ObjectId但SourceGroups不同的AzureADUser实例,仅去除ObjectId和SourceGroups均完全相同的重复项。

示例输入

var users1 = new List<AzureADUser> {
    new () { ObjectId = new Guid("Guid1"), SourceGroups = new List<Guid> {new Guid("GuidG1")}},
    new () { ObjectId = new Guid("Guid2"), SourceGroups = new List<Guid> {new Guid("GuidG2")}},
    new () { ObjectId = new Guid("Guid3"), SourceGroups = new List<Guid> {new Guid("GuidG3")}},
    new () { ObjectId = new Guid("Guid1"), SourceGroups = new List<Guid> {new Guid("GuidG4")}} // 需保留
};

var users2 = new List<AzureADUser> {
    new () { ObjectId = new Guid("Guid1"), SourceGroups = new List<Guid> {new Guid("GuidG1")}} // 需去重
};

var groupMembership1 = new GroupMembership { SourceMembers = users1 };
var groupMembership2 = new GroupMembership { SourceMembers = users2 };
var groupsMemberships = new List<GroupMembership> { groupMembership1, groupMembership2 };

期望输出

/*
ObjectId: new Guid("Guid1"), SourceGroups: new List<Guid> {new Guid("GuidG1")}
ObjectId: new Guid("Guid2"), SourceGroups: new List<Guid> {new Guid("GuidG2")}
ObjectId: new Guid("Guid3"), SourceGroups: new List<Guid> {new Guid("GuidG3")}
ObjectId: new Guid("Guid1"), SourceGroups: new List<Guid> {new Guid("GuidG4")}
*/

解决方案

方法1:自定义相等比较器配合Distinct

创建实现IEqualityComparer<AzureADUser>的比较器,明确判断两个实例是否完全相同的逻辑:

public class AzureADUserEqualityComparer : IEqualityComparer<AzureADUser>
{
    public bool Equals(AzureADUser x, AzureADUser y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        
        // 先匹配ObjectId
        if (x.ObjectId != y.ObjectId) return false;
        
        // 再匹配SourceGroups(排序后比较,避免顺序影响判断)
        if (x.SourceGroups == null && y.SourceGroups == null) return true;
        if (x.SourceGroups == null || y.SourceGroups == null) return false;
        return x.SourceGroups.OrderBy(g => g).SequenceEqual(y.SourceGroups.OrderBy(g => g));
    }

    public int GetHashCode(AzureADUser obj)
    {
        if (obj == null) return 0;
        
        var hash = obj.ObjectId.GetHashCode();
        // 结合排序后的SourceGroups哈希值,保证相同组集合的哈希一致
        if (obj.SourceGroups != null)
        {
            foreach (var guid in obj.SourceGroups.OrderBy(g => g))
            {
                hash = hash * 31 ^ guid.GetHashCode();
            }
        }
        return hash;
    }
}

修改查询代码,传入自定义比较器:

var source = groupsMemberships
    .SelectMany(x => x.SourceMembers)
    .Distinct(new AzureADUserEqualityComparer())
    .ToList();

方法2:LINQ GroupBy分组去重

无需单独定义比较器,通过匿名类型分组实现去重:

var source = groupsMemberships
    .SelectMany(x => x.SourceMembers)
    .GroupBy(u => new 
    { 
        u.ObjectId, 
        // 将排序后的组ID拼接成字符串,作为分组标识
        SourceGroupsKey = string.Join("|", u.SourceGroups?.OrderBy(g => g) ?? Enumerable.Empty<Guid>()) 
    })
    .Select(g => g.First()) // 每组取第一个实例
    .ToList();

方法3:重写AzureADUser的Equals和GetHashCode

如果该相等判断逻辑是全局通用的,直接在类中重写方法:

public class AzureADUser
{
    public Guid ObjectId { get; set; }  
    public List<Guid> SourceGroups { get; set; }

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

    public bool Equals(AzureADUser other)
    {
        if (other == null) return false;
        if (ObjectId != other.ObjectId) return false;
        
        if (SourceGroups == null && other.SourceGroups == null) return true;
        if (SourceGroups == null || other.SourceGroups == null) return false;
        return SourceGroups.OrderBy(g => g).SequenceEqual(other.SourceGroups.OrderBy(g => g));
    }

    public override int GetHashCode()
    {
        var hash = ObjectId.GetHashCode();
        if (SourceGroups != null)
        {
            foreach (var guid in SourceGroups.OrderBy(g => g))
            {
                hash = hash * 31 ^ guid.GetHashCode();
            }
        }
        return hash;
    }
}

之后直接调用Distinct即可:

var source = groupsMemberships
    .SelectMany(x => x.SourceMembers)
    .Distinct()
    .ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:40:25