1010//===----------------------------------------------------------------------===//
1111
1212/// A collection wrapper that breaks a collection into chunks based on a
13- /// predicate or projection.
14- public struct Chunked < Base: Collection , Subject> {
13+ /// predicate.
14+ ///
15+ /// Call `lazy.chunked(by:)` on a collection to create an instance of this type.
16+ public struct ChunkedBy < Base: Collection , Subject> {
1517 /// The collection that this instance provides a view onto.
1618 @usableFromInline
1719 internal let base : Base
@@ -45,7 +47,7 @@ public struct Chunked<Base: Collection, Subject> {
4547 }
4648}
4749
48- extension Chunked : LazyCollectionProtocol {
50+ extension ChunkedBy : LazyCollectionProtocol {
4951 /// A position in a chunked collection.
5052 public struct Index : Comparable {
5153 /// The range corresponding to the chunk at this position.
@@ -106,9 +108,9 @@ extension Chunked: LazyCollectionProtocol {
106108 }
107109}
108110
109- extension Chunked . Index : Hashable where Base. Index: Hashable { }
111+ extension ChunkedBy . Index : Hashable where Base. Index: Hashable { }
110112
111- extension Chunked : BidirectionalCollection
113+ extension ChunkedBy : BidirectionalCollection
112114 where Base: BidirectionalCollection
113115{
114116 /// Returns the index in the base collection of the start of the chunk ending
@@ -131,11 +133,64 @@ extension Chunked: BidirectionalCollection
131133 }
132134}
133135
134- @available ( * , deprecated, renamed: " Chunked " )
135- public typealias LazyChunked < Base: Collection , Subject> = Chunked < Base , Subject >
136+ @available ( * , deprecated, renamed: " ChunkedBy " )
137+ public typealias LazyChunked < Base: Collection , Subject> = ChunkedBy < Base , Subject >
138+
139+ @available ( * , deprecated, renamed: " ChunkedBy " )
140+ public typealias Chunked < Base: Collection , Subject> = ChunkedBy < Base , Subject >
141+
142+ /// A collection wrapper that breaks a collection into chunks based on a
143+ /// predicate.
144+ ///
145+ /// Call `lazy.chunked(on:)` on a collection to create an instance of this type.
146+ public struct ChunkedOn < Base: Collection , Subject> {
147+ @usableFromInline
148+ internal var chunked : ChunkedBy < Base , Subject >
149+
150+ @inlinable
151+ internal init (
152+ base: Base ,
153+ projection: @escaping ( Base . Element ) -> Subject ,
154+ belongInSameGroup: @escaping ( Subject , Subject ) -> Bool
155+ ) {
156+ self . chunked = ChunkedBy ( base: base, projection: projection, belongInSameGroup: belongInSameGroup)
157+ }
158+ }
159+
160+ extension ChunkedOn : LazyCollectionProtocol {
161+ public typealias Index = ChunkedBy < Base , Subject > . Index
162+
163+ @inlinable
164+ public var startIndex : Index {
165+ chunked. startIndex
166+ }
167+
168+ @inlinable
169+ public var endIndex : Index {
170+ chunked. endIndex
171+ }
172+
173+ @inlinable
174+ public subscript( position: Index ) -> ( Subject , Base . SubSequence ) {
175+ let subsequence = chunked [ position]
176+ let subject = chunked. projection ( subsequence. first!)
177+ return ( subject, subsequence)
178+ }
179+
180+ @inlinable
181+ public func index( after i: Index ) -> Index {
182+ chunked. index ( after: i)
183+ }
184+ }
185+
186+ extension ChunkedOn : BidirectionalCollection where Base: BidirectionalCollection {
187+ public func index( before i: Index ) -> Index {
188+ chunked. index ( before: i)
189+ }
190+ }
136191
137192//===----------------------------------------------------------------------===//
138- // lazy.chunked(by:)
193+ // lazy.chunked(by:) / lazy.chunked(on:)
139194//===----------------------------------------------------------------------===//
140195
141196extension LazyCollectionProtocol {
@@ -146,8 +201,8 @@ extension LazyCollectionProtocol {
146201 @inlinable
147202 public func chunked(
148203 by belongInSameGroup: @escaping ( Element , Element ) -> Bool
149- ) -> Chunked < Elements , Element > {
150- Chunked (
204+ ) -> ChunkedBy < Elements , Element > {
205+ ChunkedBy (
151206 base: elements,
152207 projection: { $0 } ,
153208 belongInSameGroup: belongInSameGroup)
@@ -160,41 +215,38 @@ extension LazyCollectionProtocol {
160215 @inlinable
161216 public func chunked< Subject: Equatable > (
162217 on projection: @escaping ( Element ) -> Subject
163- ) -> Chunked < Elements , Subject > {
164- Chunked (
218+ ) -> ChunkedOn < Elements , Subject > {
219+ ChunkedOn (
165220 base: elements,
166221 projection: projection,
167222 belongInSameGroup: == )
168223 }
169224}
170225
171226//===----------------------------------------------------------------------===//
172- // chunked(by:)
227+ // chunked(by:) / chunked(on:)
173228//===----------------------------------------------------------------------===//
174229
175230extension Collection {
176231 /// Returns a collection of subsequences of this collection, chunked by
177- /// grouping elements that project to the same value according to the given
178- /// predicate.
232+ /// the given predicate.
179233 ///
180234 /// - Complexity: O(*n*), where *n* is the length of this collection.
181235 @inlinable
182- internal func chunked< Subject> (
183- on projection: ( Element ) throws -> Subject ,
184- by belongInSameGroup: ( Subject , Subject ) throws -> Bool
236+ public func chunked(
237+ by belongInSameGroup: ( Element , Element ) throws -> Bool
185238 ) rethrows -> [ SubSequence ] {
186239 guard !isEmpty else { return [ ] }
187240 var result : [ SubSequence ] = [ ]
188241
189242 var start = startIndex
190- var subject = try projection ( self [ start] )
243+ var current = self [ start]
191244
192245 for (index, element) in indexed ( ) . dropFirst ( ) {
193- let nextSubject = try projection ( element)
194- if try ! belongInSameGroup( subject, nextSubject) {
246+ if try ! belongInSameGroup( current, element) {
195247 result. append ( self [ start..< index] )
196248 start = index
197- subject = nextSubject
249+ current = element
198250 }
199251 }
200252
@@ -204,17 +256,6 @@ extension Collection {
204256
205257 return result
206258 }
207-
208- /// Returns a collection of subsequences of this collection, chunked by
209- /// the given predicate.
210- ///
211- /// - Complexity: O(*n*), where *n* is the length of this collection.
212- @inlinable
213- public func chunked(
214- by belongInSameGroup: ( Element , Element ) throws -> Bool
215- ) rethrows -> [ SubSequence ] {
216- try chunked ( on: { $0 } , by: belongInSameGroup)
217- }
218259
219260 /// Returns a collection of subsequences of this collection, chunked by
220261 /// grouping elements that project to the same value.
@@ -223,8 +264,27 @@ extension Collection {
223264 @inlinable
224265 public func chunked< Subject: Equatable > (
225266 on projection: ( Element ) throws -> Subject
226- ) rethrows -> [ SubSequence ] {
227- try chunked ( on: projection, by: == )
267+ ) rethrows -> [ ( Subject , SubSequence ) ] {
268+ guard !isEmpty else { return [ ] }
269+ var result : [ ( Subject , SubSequence ) ] = [ ]
270+
271+ var start = startIndex
272+ var subject = try projection ( self [ start] )
273+
274+ for (index, element) in indexed ( ) . dropFirst ( ) {
275+ let nextSubject = try projection ( element)
276+ if subject != nextSubject {
277+ result. append ( ( subject, self [ start..< index] ) )
278+ start = index
279+ subject = nextSubject
280+ }
281+ }
282+
283+ if start != endIndex {
284+ result. append ( ( subject, self [ start..< endIndex] ) )
285+ }
286+
287+ return result
228288 }
229289}
230290
0 commit comments