有没有fast内置方法来检查是否IEnumerable<string>
仅包含不同的字符串?
一开始我是这样开始的:
var enumAsArray = enum.ToArray();
if (enumAsArray.Length != enumAsArray.Distinct().Count())
throw ...
然而,这看起来像是 O(2n) - 是吗?ToArray()
可能是 O(1)?
这看起来更快:
var set = new HashSet<string>();
foreach (var str in enum)
{
if (!set.Add(str))
throw ...
}
这应该是 O(n),但是,也有内置的方法吗?
编辑:也许 Distinct() 在内部使用这个?
解决方案:在考虑了所有评论和答案之后,我为第二个解决方案编写了一个扩展方法,因为这似乎是最快的版本,也是最具可读性的:
public static bool ContainsDuplicates<T>(this IEnumerable<T> e)
{
var set = new HashSet<T>();
// ReSharper disable LoopCanBeConvertedToQuery
foreach (var item in e)
// ReSharper restore LoopCanBeConvertedToQuery
{
if (!set.Add(item))
return true;
}
return false;
}
您的第二个代码示例简短、简单、明显有效,即使不是完全完美的理想解决方案,也显然相当接近它。对于您的特定问题来说,这似乎是一个完全可以接受的解决方案。
除非在您发现问题并完成性能测试后,使用该特定解决方案会导致性能问题,否则我会保持原样。考虑到总体上我认为改进的空间很小,这似乎不太可能。这不是一个足够长或复杂的解决方案,尝试找到“更短”或更简洁的解决方案将值得您花费时间和精力。
简而言之,几乎可以肯定,您的代码中有更好的地方可以花费您的时间;你已经拥有的很好。
回答您的具体问题:
-
然而,这看起来像是 O(2n) - 是吗?
是的。
-
ToArray()
可能是 O(1)?
不,这不对。
-
Maybe Distinct()
内部使用这个?
它确实使用了一个HashSet
,它看起来非常相似,但它只是忽略了重复的项目;它不会向调用者提供任何指示,表明它刚刚传递了重复的项目。因此,您需要迭代整个序列两次以查看是否删除了任何内容,而不是在遇到第一个重复项时停止。这就是总是迭代完整序列两次的东西和可能迭代完整序列一次但一旦确保答案就可以短路并停止的东西之间的区别。
-
还有内置的方法吗?
好吧,你展示了一个,它只是效率不高。我认为没有一个完整的基于 LINQ 的解决方案能像您所展示的那样高效。我能想到的最好的办法是:data.Except(data).Any()
。与常规计数相比,这比您的重复计数要好一些,因为第二次迭代可以短路(但不是第一次),但它也会迭代序列两次,并且仍然比您的非 LINQ 解决方案更糟糕,所以它仍然不是值得使用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)