If we have a sequence of Strideable
values, should we provide a way to get all the distances between them?
extension Sequence where Element: Strideable {
/// Returns a sequence consisting of the distances between each adjacent
/// pair of elements of this sequence.
///
/// - Returns: A lazily-generated sequence of the distances between each
/// element of this sequence. It will be one element shorter than this
/// one, making it empty when this sequence has less than two elements.
@inlinable
public func distances() -> LazyDistanceSequence<Element.Stride, Self> {
return LazyDistanceSequence(from: self, measuringBy: {
$0.distance(to: $1)
})
}
}
And we could provide the inverse, provide a list of values given a starting one and a sequence of distances.
extension Sequence {
/// Returns a sequence consisting of the given initial value followed by
/// advancing it by the first element of this sequence, then that result
/// advanced by the second element of this sequence, *etc.*
///
/// - Parameter start: The first element of the returned sequence.
/// - Parameter advance: A closure that combines a value of the returned
/// element type with an element of this sequence's type to give another
/// value of the returned element type.
/// - Returns: A lazily-generated sequence of the running advancement of
/// `start` and each element of the sequence. Since `start` is included,
/// the returned sequence will be one element longer than this one.
@inlinable
public func progressiveAdvancements<S: Strideable>(from start: S) -> LazyProgressivelyAdvancingSequence<S, Self> where S.Stride == Element {
return LazyProgressivelyAdvancingSequence(from: start, eachBy: self, advancingBy: {
$0.advanced(by: $1)
})
}
}
Looking at the returns, you see I generalized the idea with lazy and eager versions with custom advancing or measuring closures.
extension Sequence {
/// Returns the sequence consisting of the given initial value followed by
/// its combination with the first element of this sequence using the given
/// closure, then that result combined with the second element, *etc*,
/// copied into an instance of the given collection type.
///
/// - Parameter start: The first element of the returned sequence.
/// - Parameter type: A meta-type specifier for the returned collection
/// type.
/// - Parameter advance: A closure that combines a value of the returned
/// element type with an element of this sequence's type to give another
/// value of the returned element type.
/// - Returns: A collection of the running combination of `start` and each
/// element of the sequence. Since `start` is included, the returned
/// collection will have a length of one greater than the length of the
/// sequence.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
public func progressiveAdvancements<T, U: RangeReplaceableCollection>(from start: T, containedAs type: U.Type, advancingBy advance: (T, Element) throws -> T) rethrows -> U where U.Element == T {
var result = U(CollectionOfOne(start))
result.reserveCapacity(1 + underestimatedCount)
var iterator = makeIterator(), element = start
while let distance = iterator.next() {
element = try advance(element, distance)
result.append(element)
}
return result
}
/// Returns the sequence consisting of the distances between each adjacent
/// pair of elments, using the given closure to measure the distances, into
/// a collection of the given type.
///
/// - Parameter type: A meta-type specifier for the returned collection
/// type.
/// - Parameter measure: A closure that takes two values of the element type
/// to return the distance from the first argument to the second.
/// - Returns: A collection of the span between each element, which implies
/// a length of one less than the length of the sequence. (The returned
/// collection is empty when the sequence has less than two elements.)
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
public func distances<T: RangeReplaceableCollection>(containedAs type: T.Type, measuringBy measure: (Element, Element) throws -> T.Element) rethrows -> T {
// Can't make a delta sequence from an empty source.
var iterator = makeIterator()
guard var previous = iterator.next() else { return T() }
// Copy each measurement.
var result = T()
result.reserveCapacity(underestimatedCount)
while let current = iterator.next() {
defer { previous = current }
try result.append(measure(previous, current))
}
return result
}
}
I guess it's like the running reduce
idea from earlier this year, but more palatable since it's oriented around Strideable
.