From 0b70cac980199f99ced9e4f03530f28d011b23a1 Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Fri, 8 Aug 2025 13:47:31 -0700 Subject: [PATCH] Add labels to the tuples produced by `chunked(on:)` Label the tuple produced by `chunked(on:)` with `subject` and `chunk`. This will improve the legibility of code downstream of the said function. For example, when providing an identifier for SwiftUI's `ForEach`: ``` -ForEach(chunkedByDate, id: \.0) { date, items in +ForEach(chunkedByDate, id: \.subject) { date, items in ``` This aligns `ChunkedOnCollection` with the `IndexedCollection`, which specifies `index` and `element` as well as the built-in `EnumeratedSequence` (specifying `offset` and `element`). The introduction of the label will have no effect on existing code, because the index-based address of the tuple component will remain unchanged and absent labels will be inferred. --- Sources/Algorithms/Chunked.swift | 5 +++-- Tests/SwiftAlgorithmsTests/ChunkedTests.swift | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Sources/Algorithms/Chunked.swift b/Sources/Algorithms/Chunked.swift index 42e7d6f0..9eaed3a4 100644 --- a/Sources/Algorithms/Chunked.swift +++ b/Sources/Algorithms/Chunked.swift @@ -162,6 +162,7 @@ public struct ChunkedOnCollection { extension ChunkedOnCollection: Collection { public typealias Index = ChunkedByCollection.Index + public typealias Element = (subject: Subject, chunk: Base.SubSequence) @inlinable public var startIndex: Index { @@ -174,7 +175,7 @@ extension ChunkedOnCollection: Collection { } @inlinable - public subscript(position: Index) -> (Subject, Base.SubSequence) { + public subscript(position: Index) -> Element { let subsequence = chunked[position] // swift-format-ignore: NeverForceUnwrap // Chunks are never empty, so `.first!` is safe. @@ -509,7 +510,7 @@ extension Collection { @inlinable public func chunked( on projection: (Element) throws -> Subject - ) rethrows -> [(Subject, SubSequence)] { + ) rethrows -> [ChunkedOnCollection.Element] { guard !isEmpty else { return [] } var result: [(Subject, SubSequence)] = [] diff --git a/Tests/SwiftAlgorithmsTests/ChunkedTests.swift b/Tests/SwiftAlgorithmsTests/ChunkedTests.swift index f02ee16f..e323a830 100644 --- a/Tests/SwiftAlgorithmsTests/ChunkedTests.swift +++ b/Tests/SwiftAlgorithmsTests/ChunkedTests.swift @@ -71,6 +71,16 @@ final class ChunkedTests: XCTestCase { IndexValidator().validate(lazyChunks) } + func testChunkedOnLabels() { + let arrayChunks: Array = fruits.chunked(on: { $0.first }) + XCTAssert(arrayChunks.first!.0 == arrayChunks.first!.subject) + XCTAssert(arrayChunks.first!.1 == arrayChunks.first!.chunk) + + let lazyChunks = fruits.lazy.chunked(on: { $0.first }) + XCTAssert(lazyChunks.first!.0 == lazyChunks.first!.subject) + XCTAssert(lazyChunks.first!.1 == lazyChunks.first!.chunk) + } + func testChunkedBy() { validateFruitChunks(fruits.chunked(by: { $0.first == $1.first }))