找出IEnumerable <>是否具有唯一值的最佳方法

Glu*_*uip 12 .net c# linq

我有很多代码可以用来做这样的事情

bool GetIsUnique(IEnumerable<T> values)
{
    return values.Count() == values.Distinct().Count;
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的更快更好的方法来做到这一点?

Jam*_*iec 21

我会把它作为一个很好的扩展方法

public static bool IsUnique<T>(this IEnumerable<T> list)
{
    var hs = new HashSet<T>();
    return list.All(hs.Add);  
}
Run Code Online (Sandbox Code Playgroud)

检查是否可以将所有项目添加到HashSet.

  • 我不喜欢带有副作用的谓词"All". (5认同)
  • 副作用是无关紧要的.退出方法后抛弃hashset. (4认同)
  • @Jamiec"但...... All的实施并没有记住结果." 这本身就无关紧要了.根据定义,实现是一个实现细节.问题是:'All`****的*契约*是否与具有副作用的谓词一起使用.---当然,未来版本的linq-to-objects不太可能破坏你的代码.但它已经不适用于有序并行linq.IMO memoization是函数编程库(如linq)中的有效优化.所以我不认为这样的实现是恶意的. (3认同)
  • 但是......"All"*的实现并没有*记住结果.你是否认真考虑恶意实施All?天啊. (2认同)

Luk*_*keH 19

您的方法需要迭代序列两次,但有一些潜在的缺点:

  1. 对于任何显着大小的序列,迭代两次将比迭代一次慢.
  2. 如果您尝试多次迭代它们,某些序列将抛出异常; 其他人可能会为后续迭代返回不同的结果.
  3. 您的方法Count每次都需要迭代整个序列.一旦你知道存在重复值,就没有理由不提前爆发.

以下方法只需迭代序列一次,并在遇到任何重复值时立即提前中断:

bool GetIsUnique<T>(IEnumerable<T> values)
{
    var set = new HashSet<T>();

    foreach (T item in values)
    {
        if (!set.Add(item))
            return false;
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*Two 5

我认为如果有非唯一值,这取决于你想要做什么.@Jamiec's Or @ LukeH的答案是很好的答案,可能最适合纯粹的速度,但它无法告诉你问题在哪里.

您可能也会考虑类似的事情

var group = values.GroupBy(x => x);
return group.Any(g => g.Count() > 1);
Run Code Online (Sandbox Code Playgroud)

它本身比HashSet实施更糟糕.但是,如果你保持这个群体,你可以找到哪些元素是重复的.

var group = values.GroupBy(x => x);
return group.Where(g => g.Count() > 1);
Run Code Online (Sandbox Code Playgroud)

要么

var group = values.GroupBy(x => x);
return group.Where(g => g.Count() > 1).Select(g => g.Key);
Run Code Online (Sandbox Code Playgroud)

通过思考,GroupBy可以让您明确选择下一步做什么.但是,如果你所关心的只是知道所有的价值是否都是独一无二的,我会选择HashSet