使用Linq Union合并集合:规避空值与重复数据
使用LINQ Union合并两个集合并避免空值与重复数据
要实现这个需求,我们需要分两步走:先过滤掉无效的空值条目,再通过自定义相等逻辑实现Union去重。下面是具体的实现方案:
1. 第一步:过滤空值条目
首先,我们需要从两个集合中剔除那些关键字段为空的无效数据——比如VoteFunction、Area、Sector这些用来标识唯一性的字段,以及邮箱类字段全为空的条目(你可以根据实际业务需求调整过滤规则):
// 过滤VoteData集合中的空值 var filteredVoteData = voteDataList .Where(v => !string.IsNullOrEmpty(v.VoteFunction) && !string.IsNullOrEmpty(v.Area) && !string.IsNullOrEmpty(v.Sector) && (!string.IsNullOrEmpty(v.Email) || !string.IsNullOrEmpty(v.VoterEmail))); // 过滤DirectoryData集合中的空值 var filteredDirectoryData = directoryDataList .Where(d => !string.IsNullOrEmpty(d.VoteFunction) && !string.IsNullOrEmpty(d.Area) && !string.IsNullOrEmpty(d.Sector) && (!string.IsNullOrEmpty(d.PrimaryEmail) || !string.IsNullOrEmpty(d.VoterEmail)));
2. 第二步:合并与去重
因为VoteData和DirectoryData是不同的类,我们有两种常见的合并方式:
方式一:投影到匿名类型(简单快捷)
把两个集合投影成结构一致的匿名类型,利用匿名类型默认的属性相等性(Equals和GetHashCode会自动比较所有属性)来实现Union去重:
// 将VoteData投影为统一结构 var voteProjections = filteredVoteData.Select(v => new { v.VoteFunction, v.Area, v.Sector, Email = v.Email ?? v.VoterEmail, // 优先取Email,为空则用VoterEmail v.VoterEmail }); // 将DirectoryData投影为统一结构 var directoryProjections = filteredDirectoryData.Select(d => new { d.VoteFunction, d.Area, d.Sector, Email = d.PrimaryEmail ?? d.VoterEmail, // 优先取PrimaryEmail,为空则用VoterEmail d.VoterEmail }); // 合并并去重 var mergedResult = voteProjections.Union(directoryProjections).ToList();
方式二:转换为同一类型+自定义相等比较器(保留原始类型)
如果你需要保留VoteData类型的实例,可以先把DirectoryData转换成VoteData,再通过自定义IEqualityComparer来定义“重复”的规则:
第一步:转换DirectoryData为VoteData
var directoryAsVoteData = filteredDirectoryData.Select(d => new VoteData { Name = null, // DirectoryData没有Name字段,根据需求填充默认值或null VoteFunction = d.VoteFunction, Area = d.Area, Sector = d.Sector, Email = d.PrimaryEmail, VoterEmail = d.VoterEmail });
第二步:实现自定义相等比较器
public class VoteDataEqualityComparer : IEqualityComparer<VoteData> { public bool Equals(VoteData x, VoteData y) { if (x == null || y == null) return x == y; // 自定义重复规则:VoteFunction+Area+Sector相同,且邮箱(Email/VoterEmail)有一个匹配就算重复 return string.Equals(x.VoteFunction, y.VoteFunction, StringComparison.OrdinalIgnoreCase) && string.Equals(x.Area, y.Area, StringComparison.OrdinalIgnoreCase) && string.Equals(x.Sector, y.Sector, StringComparison.OrdinalIgnoreCase) && (string.Equals(x.Email, y.Email, StringComparison.OrdinalIgnoreCase) || string.Equals(x.VoterEmail, y.VoterEmail, StringComparison.OrdinalIgnoreCase)); } public int GetHashCode(VoteData obj) { if (obj == null) return 0; // 基于关键字段计算哈希码,确保Equals返回true的对象哈希码一致 int hash = 17; hash = hash * 23 + (obj.VoteFunction?.ToLower().GetHashCode() ?? 0); hash = hash * 23 + (obj.Area?.ToLower().GetHashCode() ?? 0); hash = hash * 23 + (obj.Sector?.ToLower().GetHashCode() ?? 0); hash = hash * 23 + (obj.Email?.ToLower().GetHashCode() ?? 0); hash = hash * 23 + (obj.VoterEmail?.ToLower().GetHashCode() ?? 0); return hash; } }
第三步:执行Union合并
var mergedResult = filteredVoteData .Union(directoryAsVoteData, new VoteDataEqualityComparer()) .ToList();
关键注意事项
- 空值过滤规则:可以根据你的实际业务调整,比如是否允许某个字段为空,或者只要有一个邮箱字段不为空就算有效。
- 重复判断逻辑:自定义比较器中的
Equals方法可以按需修改——比如如果只要VoteFunction+Area+Sector相同就算重复,就去掉邮箱的判断条件。 - 大小写敏感性:示例中用了
StringComparison.OrdinalIgnoreCase忽略大小写,如果需要区分大小写,直接使用string.Equals(x, y)即可。
内容的提问来源于stack exchange,提问作者Roshni
相关产品推荐
相关产品推荐

