Skip to content

Commit bfcb9c4

Browse files
khanlouDavide Italiano
authored andcommitted
Add count(where:) and tests (#16099)
* add count(where:) and tests * Revise count(where:) documentation * Remove errant word in abstract * add a benchmark for ranges and strings with help from @natecook1000 * update benchmark to use Array instead of Range
1 parent af63a9a commit bfcb9c4

File tree

6 files changed

+222
-0
lines changed

6 files changed

+222
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ set(SWIFT_BENCH_MODULES
5656
single-source/Chars
5757
single-source/ClassArrayGetter
5858
single-source/Combos
59+
single-source/CountAlgo
5960
single-source/DataBenchmarks
6061
single-source/DeadArray
6162
single-source/DictOfArraysToArrayOfDicts
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//===--- CountAlgo.swift --------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 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+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
import TestsUtils
13+
14+
public let CountAlgo = [
15+
BenchmarkInfo(
16+
name: "CountAlgoArray",
17+
runFunction: run_CountAlgoArray,
18+
tags: [.validation, .api]),
19+
BenchmarkInfo(
20+
name: "CountAlgoString",
21+
runFunction: run_CountAlgoString,
22+
tags: [.validation, .api]),
23+
]
24+
25+
@inline(never)
26+
public func run_CountAlgoArray(_ N: Int) {
27+
for _ in 1...10*N {
28+
CheckResults(numbers.count(where: { $0 & 4095 == 0 }) == 25)
29+
}
30+
}
31+
32+
@inline(never)
33+
public func run_CountAlgoString(_ N: Int) {
34+
let vowels = Set("aeiou")
35+
for _ in 1...5*N {
36+
CheckResults(text.count(where: vowels.contains) == 2014)
37+
}
38+
}
39+
40+
let numbers = Array(0..<100_000)
41+
42+
let text = """
43+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempus
44+
dictum tellus placerat ultrices. Proin mauris risus, eleifend a elit ut,
45+
semper consectetur nibh. Nulla ultricies est a vehicula rhoncus. Morbi
46+
sollicitudin efficitur est a hendrerit. Interdum et malesuada fames ac ante
47+
ipsum primis in faucibus. Lorem ipsum dolor sit amet, consectetur
48+
adipiscing elit. Nulla facilisi. Sed euismod sagittis laoreet. Ut elementum
49+
tempus ultrices. Donec convallis mauris at faucibus maximus.
50+
Nullam in nunc sit amet ante tristique elementum quis ut eros. Fusce
51+
dignissim, ante at efficitur dapibus, ex massa convallis nibh, et venenatis
52+
leo leo sit amet nisl. Lorem ipsum dolor sit amet, consectetur adipiscing
53+
elit. Quisque sed mi eu mi rutrum accumsan vel non massa. Nunc condimentum,
54+
arcu eget interdum hendrerit, ipsum mi pretium felis, ut mollis erat metus
55+
non est. Donec eu sapien id urna lobortis eleifend et eu ipsum. Mauris
56+
purus dolor, consequat ac nulla a, vehicula sollicitudin nulla.
57+
Phasellus a congue diam. Curabitur sed orci at sem laoreet facilisis eget
58+
quis est. Pellentesque habitant morbi tristique senectus et netus et
59+
malesuada fames ac turpis egestas. Maecenas justo tellus, efficitur id
60+
velit at, mollis pellentesque mi. Vivamus maximus nibh et ipsum porttitor
61+
facilisis. Curabitur cursus lobortis erat. Sed vitae eros et dolor feugiat
62+
consequat. In ac massa in odio gravida dignissim. Praesent aliquam gravida
63+
ullamcorper.
64+
Etiam feugiat sit amet odio sed tincidunt. Duis dolor odio, posuere at
65+
pretium sed, dignissim eu diam. Aenean eu convallis orci, vitae finibus
66+
erat. Aliquam nec mollis tellus. Morbi luctus sed quam et vestibulum.
67+
Praesent id diam tempus, consectetur tortor vel, auctor orci. Aliquam
68+
congue ex eu sagittis sodales. Suspendisse non convallis nulla. Praesent
69+
elementum semper augue, et fringilla risus ullamcorper id. Fusce eu lorem
70+
sit amet augue fermentum tincidunt. In aliquam libero sit amet dui rhoncus,
71+
ac scelerisque sem porttitor. Cras venenatis, nisi quis ullamcorper
72+
dapibus, odio dolor rutrum magna, vel pellentesque sem lectus in tellus.
73+
Proin faucibus leo iaculis nulla egestas molestie.
74+
Phasellus vitae tortor vitae erat elementum feugiat vel vel enim. Phasellus
75+
fringilla lacus sed venenatis dapibus. Phasellus sagittis vel neque ut
76+
varius. Proin aliquam, lectus sit amet auctor finibus, lorem libero
77+
pellentesque turpis, ac condimentum augue felis sit amet sem. Pellentesque
78+
pharetra nisl nec est congue, in posuere felis maximus. In ut nulla
79+
sodales, pharetra neque et, venenatis dui. Mauris imperdiet, arcu vel
80+
hendrerit vehicula, elit massa consectetur purus, eu blandit nunc orci sit
81+
amet turpis. Vestibulum ultricies id lorem id maximus. Pellentesque
82+
feugiat, lacus et aliquet consequat, mi leo vehicula justo, dapibus dictum
83+
mi quam convallis magna. Quisque id pulvinar dui, consequat gravida nisl.
84+
Nam nec justo venenatis, tincidunt enim a, iaculis odio. Maecenas eget
85+
lorem posuere, euismod nisl vel, pulvinar ex. Maecenas vitae risus ipsum.
86+
Proin congue sem ante, sit amet sagittis odio mattis sit amet. Nullam et
87+
nisi nulla.
88+
Donec vel hendrerit metus. Praesent quis finibus erat. Aliquam erat
89+
volutpat. Fusce sit amet ultricies tellus, vitae dictum dolor. Morbi auctor
90+
dolor vel ligula pretium aliquam. Aenean lobortis vel magna vel ultricies.
91+
Aenean porta urna vitae ornare porta. Quisque pretium dui diam, quis
92+
iaculis odio venenatis non. Maecenas at lacus et ligula tincidunt feugiat
93+
eu vel ipsum. Proin fermentum elit et quam tempus, eget pulvinar nisl
94+
pharetra.
95+
Mauris sodales tempus erat in lobortis. Duis vitae lacinia sapien.
96+
Pellentesque vitae massa eget orci sodales aliquet. Orci varius natoque
97+
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce
98+
nisi arcu, egestas vel consectetur eu, auctor et metus. In ultricies ligula
99+
felis, vitae pellentesque dolor tempor ac. Praesent mi magna, ultrices ut
100+
ultrices vel, sollicitudin a leo.
101+
Nam porta, nisi in scelerisque consequat, leo lacus accumsan massa,
102+
venenatis faucibus tellus quam eget tellus. Curabitur pulvinar, tellus ac
103+
facilisis consectetur, lacus lacus venenatis est, eu pretium orci augue
104+
gravida nunc. Aenean odio tellus, facilisis et finibus id, varius vitae
105+
diam. Aenean at suscipit sem. Suspendisse porta neque at nibh semper, sit
106+
amet suscipit libero egestas. Donec commodo vitae justo vitae laoreet.
107+
Suspendisse dignissim erat id ante maximus porta. Curabitur hendrerit
108+
maximus odio, et maximus felis malesuada eu. Integer dapibus finibus diam,
109+
quis convallis metus bibendum non.
110+
In vel vulputate nisi, non lacinia nunc. Nullam vitae ligula finibus,
111+
varius arcu in, pellentesque ipsum. Morbi vel velit tincidunt quam cursus
112+
lacinia non in neque. Suspendisse id feugiat nibh. Vestibulum egestas eu
113+
leo viverra fringilla. Curabitur ultrices sollicitudin libero, non sagittis
114+
felis consectetur id. Aenean non metus eget leo ornare porta sed in metus.
115+
Nullam quis fermentum sapien, sit amet sodales mi. Maecenas nec purus urna.
116+
Phasellus condimentum enim nec magna convallis, eu lacinia libero
117+
scelerisque. Suspendisse justo libero, maximus in auctor id, euismod quis
118+
risus. Nam eget augue diam. Ut id risus pulvinar elit consectetur varius.
119+
Aliquam tincidunt tortor pretium feugiat tempor. Nunc nec feugiat ex.
120+
Ut pulvinar augue eget pharetra vehicula. Phasellus malesuada tempor sem,
121+
ut tincidunt velit convallis in. Vivamus luctus libero vitae massa tempus,
122+
id elementum urna iaculis. Sed eleifend quis purus quis convallis. In
123+
rhoncus interdum mollis. Pellentesque dictum euismod felis, eget lacinia
124+
elit blandit vel. Praesent elit velit, pharetra a sodales in, cursus vitae
125+
tortor. In vitae scelerisque tellus.
126+
"""

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import CharacterProperties
4444
import Chars
4545
import ClassArrayGetter
4646
import Combos
47+
import CountAlgo
4748
import DataBenchmarks
4849
import DeadArray
4950
import DictOfArraysToArrayOfDicts
@@ -207,6 +208,7 @@ registerBenchmark(CharacterPropertiesStashedMemo)
207208
registerBenchmark(CharacterPropertiesPrecomputed)
208209
registerBenchmark(Chars)
209210
registerBenchmark(Combos)
211+
registerBenchmark(CountAlgo)
210212
registerBenchmark(ClassArrayGetter)
211213
registerBenchmark(DataBenchmarks)
212214
registerBenchmark(DeadArray)

stdlib/private/StdlibCollectionUnittest/CheckSequenceType.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ public struct FilterTest {
140140
}
141141
}
142142

143+
public struct PredicateCountTest {
144+
public let expected: Int
145+
public let sequence: [Int]
146+
public let includeElement: (Int) -> Bool
147+
public let loc: SourceLoc
148+
149+
public init(
150+
_ expected: Int,
151+
_ sequence: [Int],
152+
_ includeElement: @escaping (Int) -> Bool,
153+
file: String = #file, line: UInt = #line
154+
) {
155+
self.expected = expected
156+
self.sequence = sequence
157+
self.includeElement = includeElement
158+
self.loc = SourceLoc(file, line, comment: "test data")
159+
}
160+
}
161+
143162
public struct FindTest {
144163
public let expected: Int?
145164
public let element: MinimalEquatableValue
@@ -522,6 +541,21 @@ public let filterTests = [
522541
),
523542
]
524543

544+
public let predicateCountTests = [
545+
PredicateCountTest(
546+
0, [],
547+
{ _ -> Bool in expectUnreachable(); return true }),
548+
549+
PredicateCountTest(0, [ 0, 30, 10, 90 ], { _ -> Bool in false }),
550+
PredicateCountTest(
551+
4, [ 0, 30, 10, 90 ], { _ -> Bool in true }
552+
),
553+
PredicateCountTest(
554+
3, [ 0, 30, 10, 90 ], { (x: Int) -> Bool in x % 3 == 0 }
555+
),
556+
]
557+
558+
525559
public let findTests = [
526560
FindTest(
527561
expected: nil,

stdlib/public/core/SequenceAlgorithms.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,50 @@ extension Sequence where Element : Equatable {
572572
}
573573
}
574574

575+
//===----------------------------------------------------------------------===//
576+
// count(where:)
577+
//===----------------------------------------------------------------------===//
578+
579+
extension Sequence {
580+
/// Returns the number of elements in the sequence that satisfy the given
581+
/// predicate.
582+
///
583+
/// You can use this method to count the number of elements that pass a test.
584+
/// For example, this code finds the number of names that are fewer than
585+
/// five characters long:
586+
///
587+
/// let names = ["Jacqueline", "Ian", "Amy", "Juan", "Soroush", "Tiffany"]
588+
/// let shortNameCount = names.count(where: { $0.count < 5 })
589+
/// // shortNameCount == 3
590+
///
591+
/// To find the number of times a specific element appears in the sequence,
592+
/// use the equal-to operator (`==`) in the closure to test for a match.
593+
///
594+
/// let birds = ["duck", "duck", "duck", "duck", "goose"]
595+
/// let duckCount = birds.count(where: { $0 == "duck" })
596+
/// // duckCount == 4
597+
///
598+
/// The sequence must be finite.
599+
///
600+
/// - Parameter predicate: A closure that takes each element of the sequence
601+
/// as its argument and returns a Boolean value indicating whether
602+
/// the element should be included in the count.
603+
/// - Returns: The number of elements in the sequence that satisfy the given
604+
/// predicate.
605+
@inlinable
606+
public func count(
607+
where predicate: (Element) throws -> Bool
608+
) rethrows -> Int {
609+
var count = 0
610+
for e in self {
611+
if try predicate(e) {
612+
count += 1
613+
}
614+
}
615+
return count
616+
}
617+
}
618+
575619
//===----------------------------------------------------------------------===//
576620
// reduce()
577621
//===----------------------------------------------------------------------===//

validation-test/stdlib/SequenceType.swift.gyb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,21 @@ SequenceTypeTests.test("allSatisfy/Predicate") {
628628
}
629629
}
630630

631+
//===----------------------------------------------------------------------===//
632+
// count(where:)
633+
//===----------------------------------------------------------------------===//
634+
635+
SequenceTypeTests.test("count/Predicate") {
636+
for test in predicateCountTests {
637+
let s = MinimalSequence<OpaqueValue<Int>>(
638+
elements: test.sequence.map { OpaqueValue($0) })
639+
expectEqual(
640+
test.expected,
641+
s.count(where: { test.includeElement($0.value) }),
642+
stackTrace: SourceLocStack().with(test.loc))
643+
}
644+
}
645+
631646
//===----------------------------------------------------------------------===//
632647
// reduce()
633648
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)