【问题标题】:Empty HashSet - Count vs Any空 HashSet - 计数与任意
【发布时间】:2013-08-16 15:13:18
【问题描述】:

我只想知道 HashSet hs 是否为空。 我不想知道它到底包含多少元素。

所以我可以使用这个:

bool isEmpty = (hs.Count == 0);

...或者这个:

bool isEmpty = hs.Any(x=>true);

哪一个提供更好的结果,性能方面(特别是当 HashSet 包含大量元素时)?

【问题讨论】:

  • C# 哈希集维护一个计数,因此这比找出是否存在单个元素更有效。但是,如果您希望它是有条件的,那么 Any 总是会更好,因为它将在第一场比赛中停止。
  • 您可以只使用Any() 而不是提供 lambda。
  • 这是微优化问题,让您偏离真正的目标:编写更好的代码 :-) 使用您认为更清洁的任何内容。您还可以下载 .NET 反编译器(例如 ILSpy)并检查这两个实现。 Enumerable.Any 可能会慢一点,因为它需要实例化一个枚举器。顺便说一句,您可能想要bool isEmpty = !hs.Any();

标签: c# .net performance hashset


【解决方案1】:

HastSet<T> 实现了ICollection<T>,它有一个Count 属性,所以调用Count() 只会调用HastSet<T>.Count,我假设这是一个O(1) 操作(意思是它没有t 实际上必须 count - 它只返回 HashSet 的当前大小。

Any 将进行迭代,直到找到符合条件的项目,然后停止。

所以在你的情况下,它只会迭代一个项目,然后停止,所以 差异可能可以忽略不计

如果您有想要应用的 过滤器(例如 x => x.IsValid),那么 Any肯定更快,因为 Count(x => x.IsValid) 会遍历整个收集,而Any 将在找到匹配项后立即停止。

出于这些原因,我通常更喜欢使用Any() 而不是Count()==0,因为它更直接并且可以避免任何潜在的性能问题。我只会切换到Count()==0,前提是它比Any() 提供了显着的性能提升。

请注意,Any(x=>true) 在逻辑上与调用Any() 相同。这不会改变你的问题,但没有 lambda 看起来更干净。

【讨论】:

  • 没有。 .Any() 无参数在停止之前不会迭代。 .Any(x => x) 将因为它必须评估内容。所有无参数所要做的就是重置枚举器并调用enumerator.GetNext() 并返回它的结果以查看是否有任何结果。 .Any(x => x) 将不得不检查实际内容
  • @Tseng .Any(x=>true) 将评估第一项,发现它解析为真,然后不再评估。与.Any() 相比,这只是微不足道的工作量。使用无参数重载的主要优点是打字速度更快,并且(可以说)对读者来说更清晰。
  • 你是对的。我已经看到它返回一个常量的事实。
【解决方案2】:

在 HashSet 上,您可以同时使用两者,因为 HashSet 在内部管理计数。

但是,如果您的数据位于 IEnumerable<T>IQueryable<T> 对象中,则使用 result.Any() 优于 result.Count()(两种 Linq 方法)。

Linq 的 .Count() 将遍历整个 Enumerable,.Any() 只会在 Enumerable 中是否存在任何对象时才会查看。

更新: 只是一点点补充: 在您的情况下,使用 HashSet .Count 可能更可取,因为 .Any() 需要创建和返回 IEmumerator 如果您不打算在代码中的任何地方使用枚举器(foreach,林克等)。但我认为这将被视为“微优化”。

【讨论】:

  • Linq's .Count() will iterate through the whole Enumerable HashSet 不会。
【解决方案3】:

根据集合的类型,它可能会或可能不会影响性能。那么为什么不直接使用hs.Any(),因为它是专为您需要了解的内容而设计的呢?

而 lambda 表达式 x => true 在这里没有任何意义。你可以忽略它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    相关资源
    最近更新 更多