【问题标题】:Swift Collection underestimateCount usageSwift Collection underestimateCount 使用情况
【发布时间】:2025-11-28 06:15:01
【问题描述】:

我想知道,Collection underestimateCount 的用例是什么? Documentation 表示它与标准 Collection count 具有相同的复杂性。

/// Returns a value less than or equal to the number of elements in
/// `self`, *nondestructively*.
///
/// - Complexity: O(N).
public func underestimateCount() -> Int

但它没有说明应该在什么时候使用以及出于什么原因。

【问题讨论】:

  • How does one retrieve the element-count of a type conforming to `SequenceType`? 的可能重复项。链接问答中的答案描述了计算一些Sequence:s 需要我们迭代地使用它的生成器(swift 3:迭代器)。使用迭代器显式计算元素的数量在某些情况下实际上会消耗序列,从而破坏它。 underestimateCount() 承诺返回一个不大于实际值的计数。
  • ... 并且如答案中所述,underestimateCount() 用于集合的序列实际上将返回实际计数。
  • @dfri 这个问题是不同的,而且这个答案没有回答我的问题,而 Hamish 回答了。相似主题!= 相同。
  • 因此“可能重复...”。链接重复“足够”的问答总是好的(我相信您的问题的 answer 位于欺骗目标的 answer 范围内,但事实是目标有点过时),因为这将更容易找到这两个问题中的任何一个的答案。请注意,出于这个原因,我还添加了一个答案(重复过时)。

标签: ios swift collections


【解决方案1】:

underestimatedCount 实际上是Sequence 协议的要求,并且有a default implementation 只返回0

public var underestimatedCount: Int {
  return 0
}

但是,对于提供自己的underestimatedCount 实现的序列,这对于需要序列长度下限的逻辑很有用,而不必遍历它(请记住,Sequence 不保证非破坏性迭代)。

例如,Sequence (see its implementation here) 上的 map(_:) 方法使用 underestimateCount 来为结果数组保留初始容量:

  public func map<T>(
    _ transform: (Iterator.Element) throws -> T
  ) rethrows -> [T] {

    let initialCapacity = underestimatedCount
    var result = ContiguousArray<T>()
    result.reserveCapacity(initialCapacity) 

    // ...

这允许map(_:) 最小化重复附加到result 的成本,因为(可能)已经为其分配了初始内存块(尽管在任何情况下都值得注意ContiguousArray 有一个分摊附加成本的指数增长策略)。

但是,对于CollectionunderestimateCountthe default implementation 实际上只返回集合的count

public var underestimatedCount: Int {
    // TODO: swift-3-indexing-model - review the following
  return numericCast(count)
}

对于符合 RandomAccessCollection 的集合,这将是 O(1) 操作,否则为 O(n)。

因此,由于这种默认实现,直接使用CollectionunderestimatedCount 肯定不如使用Sequence 的常见,因为Collection 保证了无损迭代,并且在大多数情况下@ 987654346@ 只会返回count

当然,自定义集合类型可以提供它们自己的underestimatedCount 实现——给出它们包含多少元素的下限,以一种可能比count 实现更有效的方式,这可能很有用.

【讨论】:

    【解决方案2】:

    (因为我建议的重复目标有些过时)

    在 Swift 3 中,方法 underestimateCount() 已被计算属性 underestimatedCount 取代。我们可以看看implementation of the latter for Collection的源码:

      /// A value less than or equal to the number of elements in the collection.
      ///
      /// - Complexity: O(1) if the collection conforms to
      ///   `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length
      ///   of the collection.
      public var underestimatedCount: Int {
        // TODO: swift-3-indexing-model - review the following
        return numericCast(count)
      }
    
      /// The number of elements in the collection.
      ///
      /// - Complexity: O(1) if the collection conforms to
      ///   `RandomAccessCollection`; otherwise, O(*n*), where *n* is the length
      ///   of the collection.
      public var count: IndexDistance {
        return distance(from: startIndex, to: endIndex)
      }
    

    很明显underestimatedCount 只是将count 用于符合Collection 的类型(除非这些类型实现了它们自己的underestimatedCount 版本)。

    【讨论】:

    • 感谢您的回答,但它并没有告诉我为什么要使用它(通过自己实现)。
    • @KlimczakM 对于Collection (您在问题中特别要求),我自然看不出countunderestimatedCount 的默认实现之间有任何技术差异(除了数字转换),但您自然可以使用 underestimatedCount 的语义来实现您自己的版本(对于某些自定义集合),您可以允许自己实际返回一个不保证是实际的计数一个(如果这对您的自定义收藏有用)。
    • ... 但我相信underestimatedCount 的有趣用例是用于序列类型(但不是集合),尤其是新的sequence functions 可用于生成流-类似的序列不一定是有限的。对于您的自定义序列,underestimatedCount 自然可以有有用的应用程序(非消耗计数)。