我有一个对象列表,上面有一个名称字段。
我想知道是否有办法判断列表中的所有名称字段是否都是唯一的。
我可以做两个循环并遍历列表中的每个值,但我想知道是否有更简洁的方法来使用LINQ做到这一点?
我找到了一些例子,他们将列表中的每个项目与硬编码值进行比较,但在我的情况下,我想比较每个对象之间的名称字段,并获得布尔值。
答案 0 :(得分:7)
检查唯一性的一个常见“技巧”是将列表的长度与删除的重复项与原始列表的长度进行比较:
bool allNamesAreUnique = myList.Select(x => x.Name).Distinct().Count() == myList.Count();
Select(x => x.Name)
将您的列表转换为仅列出名称的列表,Distict()
删除重复项。性能应该是close to O(n)
,这比O(n²)
嵌套循环解决方案更好。
另一种选择是按名称对列表进行分组,并检查这些组的大小。这还有一个额外的好处,就是告诉你哪些值不是唯一的:
var duplicates = myList.GroupBy(x => x.Name).Where(g => g.Count() > 1);
bool hasDuplicates = duplicates.Any(); // or
List<string> duplicateNames = duplicates.Select(g => g.Key).ToList();
答案 1 :(得分:1)
虽然您可以使用LINQ进行分组或创建不同的列表,然后逐项与原始列表进行比较,但这会产生一些您可能不需要的开销,尤其是对于非常大的列表。更有效的解决方案是将密钥存储在HashSet中,HashSet具有更好的查找功能,并在单个循环中检查重复项。该解决方案仍然使用一点LINQ,因此它满足您的要求。
static public class ExtensionMethods
{
static public bool HasDuplicates<TItem,TKey>(this IEnumerable<TItem> source, Func<TItem,TKey> func)
{
var found = new HashSet<TKey>();
foreach (var key in source.Select(func))
{
if (found.Contains(key)) return true;
found.Add(key);
}
return false;
}
}
如果您要在名为Name
的字段中查找重复项,请按以下方式使用:
var hasDuplicates = list.HasDuplicates( item => item.Name );
如果您想要不区分大小写:
var hasDuplicates = list.HasDuplicates( item => item.Name.ToUpper() );