我可以使用LINQ来查明列表中的给定属性是否重复?

时间:2018-06-18 15:44:56

标签: c# linq

我有一个对象列表,上面有一个名称字段。

我想知道是否有办法判断列表中的所有名称字段是否都是唯一的。

我可以做两个循环并遍历列表中的每个值,但我想知道是否有更简洁的方法来使用LINQ做到这一点?

我找到了一些例子,他们将列表中的每个项目与硬编码值进行比较,但在我的情况下,我想比较每个对象之间的名称字段,并获得布尔值。

2 个答案:

答案 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() );