I'm trying to convert some Python code to Swift and wondering if there is an existing function to calculate the difference between successive elements in a Swift array. For example:
diff([1,3,5,6,10]) would return [2,2,1,4]
I'm trying to convert some Python code to Swift and wondering if there is an existing function to calculate the difference between successive elements in a Swift array. For example:
diff([1,3,5,6,10]) would return [2,2,1,4]
No, but it could be very easily implemented:
let a = [1, 3, 5, 6, 10]
zip(a.dropFirst(), a).map(-) // => [2, 2, 1, 4]
It's simple enough that it's probably not worth wrapping into a function, but if you insist:
extension Collection where Element: Numeric {
func diff() -> [Element] {
return zip(self.dropFirst(), self).map(-)
}
}
[1, 3, 5, 6, 10].diff() // => [2, 2, 1, 4]
If you need the result to be lazily evaluated, you can do this:
extension Collection where Element: Numeric {
func diff() -> AnyCollection<Element> {
return AnyCollection(zip(self.dropFirst(), self).lazy.map(-))
}
}
You can use reduce(into:) combined with dropfirst to achieve what you want:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().reduce(into: []) {
$0.append($1 - last)
last = $1
}
}
}
Another option is to use map and defer:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().map { element in
defer { last = element }
return element - last
}
}
}
let arr = [1,3,5,6,10]
print(arr.diff()) // "[2, 2, 1, 4]\n"
There's no built in function for this, but you can easily implement it recursively. Thanks for the HeadTail
extension for @Alexander.
extension Array {
func headTail<ReturnType>(_ closure: (Element?, [Element]) -> ReturnType) -> ReturnType {
return closure(self.first, Array(self.dropFirst()))
}
}
extension Array where Element == Int {
func diff() -> [Int] {
return self.headTail { head, tail in
guard let head = head, let next = tail.first else { return [] } //base case, empty list
return [next - head] + tail.diff()
}
}
}