如何使用LINQ基于字符串数组属性去重RowData类对象列表?
基于LINQ筛选Aliases属性不重复的RowData列表
先看你的原始代码和需求:
class RowData { string Name; string[] Aliases; } List<RowData> rowData = new List<RowData>(); rowData.Add(new RowData { Name = "John Doe", Aliases = new string[] { "johndoe", "jdoe" } }); rowData.Add(new RowData { Name = "Jane Doe", Aliases = new string[] { "janedoe", "jdoe" } }); rowData.Add(new RowData { Name = "John Doe", Aliases = new string[] { "johndoe", "jdoe" } }); List<string[]> aliasList; foreach(var row in rowData) { if(aliasList.Any(obj => obj.SequenceEqual(row.Aliases))) { continue; } aliasList.Add(row.Aliases); MakeRow(row.Name, row.Aliases); }
需求是保留列表中Aliases属性不重复的项,最终只保留索引0和1的元素(索引0和2的Aliases完全一致)。
你当前的foreach方案可以实现需求,但用LINQ能写出更简洁、可读性更强的代码,下面提供两种可行的LINQ实现方式:
方式一:自定义比较器结合Distinct方法
先实现针对RowData的相等比较器,专门通过Aliases数组的内容(顺序敏感)判断是否相等:
public class RowDataAliasComparer : IEqualityComparer<RowData> { public bool Equals(RowData x, RowData y) { if (x == null || y == null) return x == y; // 用SequenceEqual判断数组内容和顺序是否完全一致 return x.Aliases.SequenceEqual(y.Aliases); } public int GetHashCode(RowData obj) { if (obj.Aliases == null) return 0; // 计算数组哈希码,确保相同内容(顺序一致)的数组哈希码相同 int hash = 17; foreach (var alias in obj.Aliases) { hash = hash * 31 + (alias?.GetHashCode() ?? 0); } return hash; } }
然后直接用LINQ的Distinct方法筛选唯一项:
var uniqueRows = rowData.Distinct(new RowDataAliasComparer()).ToList(); // 遍历处理唯一项 foreach (var row in uniqueRows) { MakeRow(row.Name, row.Aliases); }
方式二:用DistinctBy结合数组比较器(.NET 6+支持)
如果使用.NET 6及以上版本,可借助DistinctBy方法配合通用数组比较器,逻辑更通用、可复用:
public class ArrayEqualityComparer<T> : IEqualityComparer<T[]> { public bool Equals(T[] x, T[] y) { if (x == null || y == null) return x == y; return x.SequenceEqual(y); } public int GetHashCode(T[] obj) { if (obj == null) return 0; int hash = 17; foreach (var item in obj) { hash = hash * 31 + (item?.GetHashCode() ?? 0); } return hash; } }
调用DistinctBy指定用Aliases作为去重键:
var uniqueRows = rowData.DistinctBy(row => row.Aliases, new ArrayEqualityComparer<string>()).ToList(); foreach (var row in uniqueRows) { MakeRow(row.Name, row.Aliases); }
这两种LINQ方案的优势:
- 代码简洁直观,逻辑一目了然
- 比较逻辑封装到单独类中,模块化程度高,方便后续复用
- 避免手动维护
aliasList的繁琐,减少出错概率(比如你原代码中aliasList未初始化会直接报错)
内容的提问来源于stack exchange,提问作者JDK
相关产品推荐
相关产品推荐

