Skip to content

Commit 9f62800

Browse files
author
Tim Vermeulen
authored
Ensure chunked(by:) always compares consecutive elements (apple#162)
1 parent dcc3c82 commit 9f62800

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

Sources/Algorithms/Chunked.swift

+14-8
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ extension ChunkedBy: LazyCollectionProtocol {
7777
/// at the given index.
7878
@inlinable
7979
internal func endOfChunk(startingAt start: Base.Index) -> Base.Index {
80-
let subject = projection(base[start])
81-
return base[base.index(after: start)...]
82-
.endOfPrefix(while: { belongInSameGroup(subject, projection($0)) })
80+
var subject = projection(base[start])
81+
82+
return base[base.index(after: start)...].endOfPrefix(while: { element in
83+
let nextSubject = projection(element)
84+
defer { subject = nextSubject }
85+
return belongInSameGroup(subject, nextSubject)
86+
})
8387
}
8488

8589
@inlinable
@@ -118,11 +122,13 @@ extension ChunkedBy: BidirectionalCollection
118122
@inlinable
119123
internal func startOfChunk(endingAt end: Base.Index) -> Base.Index {
120124
let indexBeforeEnd = base.index(before: end)
125+
var subject = projection(base[indexBeforeEnd])
121126

122-
// Get the projected value of the last element in the range ending at `end`.
123-
let subject = projection(base[indexBeforeEnd])
124-
return base[..<indexBeforeEnd]
125-
.startOfSuffix(while: { belongInSameGroup(projection($0), subject) })
127+
return base[..<indexBeforeEnd].startOfSuffix(while: { element in
128+
let nextSubject = projection(element)
129+
defer { subject = nextSubject }
130+
return belongInSameGroup(nextSubject, subject)
131+
})
126132
}
127133

128134
@inlinable
@@ -246,8 +252,8 @@ extension Collection {
246252
if try !belongInSameGroup(current, element) {
247253
result.append(self[start..<index])
248254
start = index
249-
current = element
250255
}
256+
current = element
251257
}
252258

253259
if start != endIndex {

Tests/SwiftAlgorithmsTests/ChunkedTests.swift

+19
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ final class ChunkedTests: XCTestCase {
7878
validateIndexTraversals(lazyChunks)
7979
}
8080

81+
func testChunkedByComparesConsecutiveElements() {
82+
XCTAssertEqualSequences(
83+
[1, 2, 3, 4, 6, 7, 8, 9].chunked(by: { $1 - $0 == 1 }),
84+
[[1, 2, 3, 4], [6, 7, 8, 9]])
85+
86+
XCTAssertEqualSequences(
87+
[1, 2, 3, 4, 6, 7, 8, 9].lazy.chunked(by: { $1 - $0 == 1 }),
88+
[[1, 2, 3, 4], [6, 7, 8, 9]])
89+
90+
print(Array([1, 2, 3].lazy.chunked(by: { $1 - $0 == 1 })))
91+
print(Array([1, 2, 3].lazy.chunked(by: { $1 - $0 == 1 }).reversed()))
92+
93+
XCTAssertEqualSequences(
94+
[1, 2, 3, 4, 6, 7, 8, 9].lazy.chunked(by: { $1 - $0 == 1 }).reversed(),
95+
[[6, 7, 8, 9], [1, 2, 3, 4]])
96+
97+
validateIndexTraversals([1, 2, 3].lazy.chunked(by: { $1 - $0 == 1 }))
98+
}
99+
81100
func testChunkedLazy() {
82101
XCTAssertLazySequence(fruits.lazy.chunked(by: { $0.first == $1.first }))
83102
XCTAssertLazySequence(fruits.lazy.chunked(on: { $0.first }))

0 commit comments

Comments
 (0)