-
Notifications
You must be signed in to change notification settings - Fork 442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Evenly divide a collection into chunks #96
Conversation
29e66be
to
c39216d
Compare
4c03fb7
to
88d0450
Compare
88d0450
to
b1d26ce
Compare
@swift-ci please test |
b1d26ce
to
c6233a4
Compare
I tried for a bit to make It is important that print(Array((0..<3).evenlyChunked(into: 5)))
// [0..<1, 1..<2, 2..<3, 3..<3, 3..<3] At the same time, every collection subsequence needs to share its indices with the collection it came from, in particular: let chunks = (0..<6).evenlyChunked(into: 2)
let index = chunks.index(after: chunks.startIndex)
let slice = chunks[index...]
print(index == slice.startIndex) // should print "true" This is problematic because the slice doesn't know it's a slice, and so it assigns its |
@swift-ci please test |
/// Returns the base distance between two `EvenChunks` indices from the end | ||
/// of one to the start of the other, when given their offsets. | ||
func baseDistance(from offsetA: Int, to offsetB: Int) -> Int { | ||
let smallChunkSize = baseCount / numberOfChunks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @timvermeulen :)
Should we safe guard by a 0
value in numberOfChunks
? The following code for example
let ec = "".evenlyChunked(into: 0)
let d = ec.index(ec.startIndex, offsetBy: 1)
could lead to a division by zero.
Given that should fail anyways because we cannot advance that, should we just precondition
that instead of fail in division by zero? WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you pointed out, it's fine (or even desired) for the program to crash in that scenario since it's a programmer error to advance past the end. Division by zero doesn't have the most descriptive error message, but other than that it's a totally reasonable way to crash.
Advancing past the end (or before the start) isn't required to crash in any particular way, in fact, it isn't required to crash at all: Array
is a common example of a collection that is totally fine with you moving an index outside the bounds of the collection, as long as you don't use it to try to index the array. In the Algorithms package we try to be a lot more vigilant about making sure the program crashes when an invalid index is used for subscripting, than about whatever happens when you try to move out of bounds (usually deferring to however the base collection handles it).
Note that in this particular case the division by zero only happens when the number of chunks is 0 — when moving past the end of, say, [1, 2, 3].evenlyChunked(into: 2)
using index(_:offsetBy:)
, no crash happens at all. index(_:offsetBy:)
is probably where the change should be made if we wanted to be more strict about this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok! Thanks :)
Division by zero doesn't have the most descriptive error message, but other than that it's a totally reasonable way to crash.
That is what I was thinking with the precondition suggestion, if we will crash, it seems a smoother way to crash from the user perspective since we can give a better error message. But agree, it is totally fine.
Sources/Algorithms/Chunked.swift
Outdated
internal var firstUpperBound: Base.Index | ||
|
||
@inlinable | ||
internal init( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Is this init method being used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not anymore, good catch!
I think I like
|
@swift-ci please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🚢
let start = startOfChunk(endingAt: end, offset: offset) | ||
return Index(start..<end, offset: offset) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These helpers are great! 👏🏻
@swift-ci Please test |
Divide a collection into a given number of chunks as evenly as possible, with larger chunks at the start.
EvenChunks<Base>.SubSequence
is set to beEvenChunks<Base.SubSequence>
which works out rather nicely. Other collections in this package that could benefit from this as well areLazyChunked
,ChunkedByCount
, andWindows
.Checklist