【问题标题】:Checking a list with null values for duplicates in C#在 C# 中检查具有空值的列表是否存在重复项
【发布时间】:2013-06-06 11:04:03
【问题描述】:

在 C# 中,我可以使用类似的东西:

List<string> myList = new List<string>();

if (myList.Count != myList.Distinct().Count())
{
    // there are duplicates
}

检查列表中的重复元素。但是,当列表中有 null 项目时,这会产生误报。我可以使用一些缓慢的代码来做到这一点,但是有没有办法检查列表中的重复项,同时以简洁的方式忽略空值?

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    如果您担心性能问题,以下代码将在找到第一个重复项后立即停止 - 到目前为止,所有其他解决方案都要求整个输入至少迭代一次。

    var hashset = new HashSet<string>();
    if (myList.Where(s => s != null).Any(s => !hashset.Add(s)))
    {
        // there are duplicates
    }
    

    hashset.Add 返回 false 如果该项目已经存在于集合中,Any 在第一个 true 值出现时返回 true,所以这只会搜索输入直到第一个重复。

    【讨论】:

    • 我认为GroupBy 被推迟了?
    • @Jodrell 它会延迟到您尝试读取第一组的时间点,此时它会读取整个输入序列,对其进行分组,然后返回第一组。
    • 在这种情况下,HashSet 是必需的。
    • +1 这将为非常大的集合提供最佳性能。但由于创建/更新/重新分配 HashSet 的开销,不一定适用于小型集合。
    • @Joe Distinct 在底层使用 HashSet 时做同样的事情,GroupBy 也会做类似的事情。
    【解决方案2】:

    我会这样做:

    鉴于 Linq 语句将被延迟评估,.Any 将短路 - 这意味着如果有重复,您不必迭代和计算整个列表 - 因此应该更有效。

    var dupes = myList
        .Where(item => item != null)
        .GroupBy(item => item)
        .Any(g => g.Count() > 1);
    
    if(dupes)
    {
        //there are duplicates
    }
    

    编辑:http://pastebin.com/b9reVaJu 一些 Linqpad 基准测试似乎Count() 结束 GroupBy 更快

    编辑 2:以下 Rawling 的回答似乎比这种方法至少快 5 倍!

    【讨论】:

    • +1 我更喜欢这个而不是其他答案,对我来说似乎更简洁。
    • Any 仍然要求整个输入至少被迭代一次(以构建组),并且它的某些部分被第二次迭代(以检查组的长度 - 尽管再三考虑,也许这些组可以在不迭代的情况下短路Count)——而可以最多对整个输入进行一次迭代来执行此检查。
    • @Rawling 我假设因为 Count() 被评估为“任何”的一部分 - 它会懒惰地评估分组 - 我们如何测试这个?很有趣!
    • 嗯,你可以使用ILSpy来寻找GroupBy的实现,但是这样想——GroupBy在返回第一组之前,需要消耗整个输入序列,以确保它具有将进入该组的所有项目。
    • @Jodrell 我希望立即,因为DistinctGroupBy 也需要建立某种值的散列。
    【解决方案3】:
    var nonNulls = myList.Where(x => x != null)
    if (nonNulls.Count() != nonNulls.Distinct().Count())
    {
        // there are duplicates
    }
    

    【讨论】:

    • 这会迭代列表两次
    【解决方案4】:

    嗯,两个空值是重复的,不是吗?

    不管怎样,比较不带空值的列表:

    var denullified = myList.Where(l => l != null);
    if(denullified.Count() != denullified.Distinct().Count()) ...
    

    【讨论】:

    • 我能想到很多不考虑空值重复的情况。我们有一个网站,用户可以通过电子邮件或(可选)用户名登录。没有用户名的用户用户名为空,但用户名不能重复。
    【解决方案5】:

    编辑我的第一次尝试很糟糕,因为它没有被推迟。

    相反,

    var duplicates = myList
        .Where(item => item != null)
        .GroupBy(item => item)
        .Any(g => g.Skip(1).Any());
    

    删除了较差的实现。

    【讨论】:

    • @svick 然而,这还不够懒惰。
    猜你喜欢
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2019-03-19
    相关资源
    最近更新 更多