| 
 | 1 | +//===----------------------------------------------------------------------===//  | 
 | 2 | +//  | 
 | 3 | +// This source file is part of the Swift Algorithms open source project  | 
 | 4 | +//  | 
 | 5 | +// Copyright (c) 2020 Apple Inc. and the Swift project authors  | 
 | 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception  | 
 | 7 | +//  | 
 | 8 | +// See https://swift.org/LICENSE.txt for license information  | 
 | 9 | +//  | 
 | 10 | +//===----------------------------------------------------------------------===//  | 
 | 11 | + | 
 | 12 | +//===----------------------------------------------------------------------===//  | 
 | 13 | +// contains(countIn:where:)  | 
 | 14 | +//===----------------------------------------------------------------------===//  | 
 | 15 | + | 
 | 16 | +extension Sequence {  | 
 | 17 | +  /// Returns whether or not the number of elements of the sequence that satisfy  | 
 | 18 | +  /// the given predicate fall within a given range.  | 
 | 19 | +  ///  | 
 | 20 | +  /// The following example determines if there are multiple (at least two)  | 
 | 21 | +  /// types of animals with “lion” in its name:  | 
 | 22 | +  ///  | 
 | 23 | +  ///     let animals = [  | 
 | 24 | +  ///         "mountain lion",  | 
 | 25 | +  ///         "lion",  | 
 | 26 | +  ///         "snow leopard",  | 
 | 27 | +  ///         "leopard",  | 
 | 28 | +  ///         "tiger",  | 
 | 29 | +  ///         "panther",  | 
 | 30 | +  ///         "jaguar"  | 
 | 31 | +  ///     ]  | 
 | 32 | +  ///     print(animals.contains(countIn: 2..., where: { $0.contains("lion") }))  | 
 | 33 | +  ///     // prints "true"  | 
 | 34 | +  ///  | 
 | 35 | +  /// - Parameters:  | 
 | 36 | +  ///   - rangeExpression: The range of acceptable counts  | 
 | 37 | +  ///   - predicate: A closure that takes an element as its argument and returns  | 
 | 38 | +  ///   a Boolean value indicating whether the element should be included in the  | 
 | 39 | +  ///   count.  | 
 | 40 | +  /// - Returns: Whether or not the number of elements in the sequence that  | 
 | 41 | +  /// satisfy the given predicate is within a given range  | 
 | 42 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 43 | +  @inlinable  | 
 | 44 | +  public func contains<R: RangeExpression>(  | 
 | 45 | +    countIn rangeExpression: R,  | 
 | 46 | +    where predicate: (Element) throws -> Bool  | 
 | 47 | +  ) rethrows -> Bool where R.Bound: FixedWidthInteger {  | 
 | 48 | +    let range = rangeExpression.relative(to: R.Bound.zero..<R.Bound.max)  | 
 | 49 | +      | 
 | 50 | +    // If the upper bound is less than the max value, iteration can stop once it  | 
 | 51 | +    // reaches the range’s upper bound and return `false`, since the bounds have  | 
 | 52 | +    // been exceeded.  | 
 | 53 | +    // Otherwise, treat the range as unbounded. As soon as the count reaches the  | 
 | 54 | +    // range’s lower bound, iteration can stop and return `true`.  | 
 | 55 | +    let threshold: R.Bound  | 
 | 56 | +    let thresholdReturn: Bool  | 
 | 57 | +    if range.upperBound < R.Bound.max {  | 
 | 58 | +      threshold = range.upperBound  | 
 | 59 | +      thresholdReturn = false  | 
 | 60 | +    } else {  | 
 | 61 | +      threshold = range.lowerBound  | 
 | 62 | +      thresholdReturn = true  | 
 | 63 | +    }  | 
 | 64 | +      | 
 | 65 | +    var count: R.Bound = .zero  | 
 | 66 | +    for element in self {  | 
 | 67 | +      if try predicate(element) {  | 
 | 68 | +        count += 1  | 
 | 69 | +          | 
 | 70 | +        // Return early if we’ve reached the threshold.  | 
 | 71 | +        if count >= threshold {  | 
 | 72 | +          return thresholdReturn  | 
 | 73 | +        }  | 
 | 74 | +      }  | 
 | 75 | +    }  | 
 | 76 | +      | 
 | 77 | +    return range.contains(count)  | 
 | 78 | +  }  | 
 | 79 | +}  | 
 | 80 | + | 
 | 81 | +//===----------------------------------------------------------------------===//  | 
 | 82 | +// contains(exactly:where:)  | 
 | 83 | +// contains(atLeast:where:)  | 
 | 84 | +// contains(moreThan:where:)  | 
 | 85 | +// contains(lessThan:where:)  | 
 | 86 | +// contains(lessThanOrEqualTo:where:)  | 
 | 87 | +//===----------------------------------------------------------------------===//  | 
 | 88 | + | 
 | 89 | +extension Sequence {  | 
 | 90 | +  /// Returns whether or not an exact number of elements of the sequence satisfy  | 
 | 91 | +  /// the given predicate.  | 
 | 92 | +  ///  | 
 | 93 | +  /// The following example determines if there are exactly two bears:  | 
 | 94 | +  ///  | 
 | 95 | +  ///     let animals = [  | 
 | 96 | +  ///         "bear",  | 
 | 97 | +  ///         "fox",  | 
 | 98 | +  ///         "bear",  | 
 | 99 | +  ///         "squirrel",  | 
 | 100 | +  ///         "bear",  | 
 | 101 | +  ///         "moose",  | 
 | 102 | +  ///         "squirrel",  | 
 | 103 | +  ///         "elk"  | 
 | 104 | +  ///     ]  | 
 | 105 | +  ///     print(animals.contains(exactly: 2, where: { $0 == "bear" }))  | 
 | 106 | +  ///     // prints "false"  | 
 | 107 | +  ///  | 
 | 108 | +  /// Using `contains(exactly:where:)` is faster than using `filter(where:)` and  | 
 | 109 | +  /// comparing its `count` using `==` because this function can return early,  | 
 | 110 | +  /// without needing to iterating through all elements to get an exact count.  | 
 | 111 | +  /// If, and as soon as, the count exceeds 2, it returns `false`.  | 
 | 112 | +  ///  | 
 | 113 | +  /// - Parameter exactCount: The exact number to expect  | 
 | 114 | +  /// - Parameter predicate: A closure that takes an element as its argument and  | 
 | 115 | +  /// returns a Boolean value indicating whether the element should be included  | 
 | 116 | +  /// in the count.  | 
 | 117 | +  /// - Returns: Whether or not exactly `exactCount` number of elements in the  | 
 | 118 | +  /// sequence passed `predicate`  | 
 | 119 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 120 | +  @inlinable  | 
 | 121 | +  public func contains(  | 
 | 122 | +    exactly exactCount: Int,  | 
 | 123 | +    where predicate: (Element) throws -> Bool  | 
 | 124 | +  ) rethrows -> Bool {  | 
 | 125 | +    return try self.contains(countIn: exactCount...exactCount, where: predicate)  | 
 | 126 | +  }  | 
 | 127 | +    | 
 | 128 | +  /// Returns whether or not at least a given number of elements of the sequence  | 
 | 129 | +  /// satisfy the given predicate.  | 
 | 130 | +  ///  | 
 | 131 | +  /// The following example determines if there are at least two numbers that  | 
 | 132 | +  /// are a multiple of 3:  | 
 | 133 | +  ///  | 
 | 134 | +  ///     let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  | 
 | 135 | +  ///     print(numbers.contains(atLeast: 2, where: { $0.isMultiple(of: 3) }))  | 
 | 136 | +  ///     // prints "true"  | 
 | 137 | +  ///  | 
 | 138 | +  /// Using `contains(atLeast:where:)` is faster than using `filter(where:)` and  | 
 | 139 | +  /// comparing its `count` using `>=` because this function can return early,  | 
 | 140 | +  /// without needing to iterating through all elements to get an exact count.  | 
 | 141 | +  /// If, and as soon as, the count reaches 2, it returns `true`.  | 
 | 142 | +  ///  | 
 | 143 | +  /// - Parameter minimumCount: The minimum number to count before returning  | 
 | 144 | +  /// - Parameter predicate: A closure that takes an element as its argument and  | 
 | 145 | +  /// returns a Boolean value indicating whether the element should be included  | 
 | 146 | +  /// in the count.  | 
 | 147 | +  /// - Returns: Whether or not at least `minimumCount` number of elements in  | 
 | 148 | +  /// the sequence passed `predicate`  | 
 | 149 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 150 | +  @inlinable  | 
 | 151 | +  public func contains(  | 
 | 152 | +    atLeast minimumCount: Int,  | 
 | 153 | +    where predicate: (Element) throws -> Bool  | 
 | 154 | +  ) rethrows -> Bool {  | 
 | 155 | +    return try self.contains(countIn: minimumCount..., where: predicate)  | 
 | 156 | +  }  | 
 | 157 | +    | 
 | 158 | +  /// Returns whether or not more than a given number of elements of the  | 
 | 159 | +  /// sequence satisfy the given predicate.  | 
 | 160 | +  ///  | 
 | 161 | +  /// The following example determines if there are more than two numbers that  | 
 | 162 | +  /// are a multiple of 3:  | 
 | 163 | +  ///  | 
 | 164 | +  ///     let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  | 
 | 165 | +  ///     print(numbers.contains(moreThan: 2, where: { $0.isMultiple(of: 3) }))  | 
 | 166 | +  ///     // prints "true"  | 
 | 167 | +  ///  | 
 | 168 | +  /// Using `contains(moreThan:where:)` is faster than using `filter(where:)`  | 
 | 169 | +  /// and comparing its `count` using `>` because this function can return  | 
 | 170 | +  /// early, without needing to iterating through all elements to get an exact  | 
 | 171 | +  /// count. If, and as soon as, the count reaches 2, it returns `true`.  | 
 | 172 | +  ///  | 
 | 173 | +  /// - Parameter minimumCount: The minimum number to count before returning  | 
 | 174 | +  /// - Parameter predicate: A closure that takes an element as its argument and  | 
 | 175 | +  /// returns a Boolean value indicating whether the element should be included  | 
 | 176 | +  /// in the count.  | 
 | 177 | +  /// - Returns: Whether or not more than `minimumCount` number of elements in  | 
 | 178 | +  /// the sequence passed `predicate`  | 
 | 179 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 180 | +  @inlinable  | 
 | 181 | +  public func contains(  | 
 | 182 | +    moreThan minimumCount: Int,  | 
 | 183 | +    where predicate: (Element) throws -> Bool  | 
 | 184 | +  ) rethrows -> Bool {  | 
 | 185 | +    return try self.contains(countIn: (minimumCount + 1)..., where: predicate)  | 
 | 186 | +  }  | 
 | 187 | +    | 
 | 188 | +  /// Returns whether or not fewer than a given number of elements of the  | 
 | 189 | +  /// sequence satisfy the given predicate.  | 
 | 190 | +  ///  | 
 | 191 | +  /// The following example determines if there are fewer than five numbers in  | 
 | 192 | +  /// the sequence that are multiples of 10:  | 
 | 193 | +  ///  | 
 | 194 | +  ///     let numbers = [1, 2, 5, 10, 20, 50, 100, 1, 1, 5, 2]  | 
 | 195 | +  ///     print(numbers.contains(lessThan: 5, where: { $0.isMultiple(of: 10) }))  | 
 | 196 | +  ///     // prints "true"  | 
 | 197 | +  ///  | 
 | 198 | +  /// Using `contains(moreThan:where:)` is faster than using `filter(where:)`  | 
 | 199 | +  /// and comparing its `count` using `>` because this function can return  | 
 | 200 | +  /// early, without needing to iterating through all elements to get an exact  | 
 | 201 | +  /// count. If, and as soon as, the count reaches 2, it returns `true`.  | 
 | 202 | +  ///  | 
 | 203 | +  /// - Parameter maximumCount: The maximum number to count before returning  | 
 | 204 | +  /// - Parameter predicate: A closure that takes an element as its argument and  | 
 | 205 | +  /// returns a Boolean value indicating whether the element should be included  | 
 | 206 | +  /// in the count.  | 
 | 207 | +  /// - Returns: Whether or not less than `maximumCount` number of elements in  | 
 | 208 | +  /// the sequence passed `predicate`  | 
 | 209 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 210 | +  @inlinable  | 
 | 211 | +  public func contains(  | 
 | 212 | +    lessThan maximumCount: Int,  | 
 | 213 | +    where predicate: (Element) throws -> Bool  | 
 | 214 | +  ) rethrows -> Bool {  | 
 | 215 | +    return try self.contains(countIn: ..<maximumCount, where: predicate)  | 
 | 216 | +  }  | 
 | 217 | +    | 
 | 218 | +  /// Returns whether or not the number of elements of the sequence that satisfy  | 
 | 219 | +  /// the given predicate is less than or equal to a given number.  | 
 | 220 | +  ///  | 
 | 221 | +  /// The following example determines if there are less than or equal to five  | 
 | 222 | +  /// numbers in the sequence that are multiples of 10:  | 
 | 223 | +  ///  | 
 | 224 | +  ///     let numbers = [1, 2, 5, 10, 20, 50, 100, 1000, 1, 1, 5, 2]  | 
 | 225 | +  ///     print(numbers.contains(lessThanOrEqualTo: 5, where: {  | 
 | 226 | +  ///         $0.isMultiple(of: 10)  | 
 | 227 | +  ///     }))  | 
 | 228 | +  ///     // prints "true"  | 
 | 229 | +  ///  | 
 | 230 | +  /// Using `contains(lessThanOrEqualTo:where:)` is faster than using  | 
 | 231 | +  /// `filter(where:)` and comparing its `count` with `>` because this function  | 
 | 232 | +  /// can return early, without needing to iterating through all elements to get  | 
 | 233 | +  /// an exact count. If, and as soon as, the count exceeds `maximumCount`,  | 
 | 234 | +  /// it returns `false`.  | 
 | 235 | +  ///  | 
 | 236 | +  /// - Parameter maximumCount: The maximum number to count before returning  | 
 | 237 | +  /// - Parameter predicate: A closure that takes an element as its argument and  | 
 | 238 | +  /// returns a Boolean value indicating whether the element should be included  | 
 | 239 | +  /// in the count.  | 
 | 240 | +  /// - Returns: Whether or not the number of elements that pass `predicate` is  | 
 | 241 | +  /// less than or equal to `maximumCount`  | 
 | 242 | +  /// the sequence passed `predicate`  | 
 | 243 | +  /// - Complexity: Worst case O(*n*), where *n* is the number of elements.  | 
 | 244 | +  @inlinable  | 
 | 245 | +  public func contains(  | 
 | 246 | +    lessThanOrEqualTo maximumCount: Int,  | 
 | 247 | +    where predicate: (Element) throws -> Bool  | 
 | 248 | +  ) rethrows -> Bool {  | 
 | 249 | +    return try self.contains(countIn: ...maximumCount, where: predicate)  | 
 | 250 | +  }  | 
 | 251 | +}  | 
0 commit comments