Skip to content

Instantly share code, notes, and snippets.

@Kdan
Last active December 9, 2021 03:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kdan/aa99e46f998e15232d58572bb7e0d885 to your computer and use it in GitHub Desktop.
Save Kdan/aa99e46f998e15232d58572bb7e0d885 to your computer and use it in GitHub Desktop.
A Swift Playground for total distance functions on lists of CLLocation objects. https://medium.com/@kewindannerfjordremeczki/swift-4-2-corelocation-total-distance-traveled-ff881ba2a1ce
import CoreLocation
/// The locations used for the examples.
let locations = [CLLocation(latitude: 10.0, longitude: 12.0),
CLLocation(latitude: 10.1, longitude: 12.0),
CLLocation(latitude: 10.2, longitude: 12.0),
CLLocation(latitude: 10.1, longitude: 12.0)]
/* A BOILERPLATE SOLUTION */
func totalDistance(of locations: [CLLocation]) -> CLLocationDistance {
var distance: CLLocationDistance = 0.0
var previousLocation: CLLocation?
locations.forEach { location in
if let previousLocation = previousLocation {
distance += location.distance(from: previousLocation)
}
previousLocation = location
}
return distance
}
print(totalDistance(of: locations)) // Prints 33182.563139193335
/* A RECURSIVE SOLUTION */
var mutableLocations = locations
func totalDistance(initialDistance: CLLocationDistance, initialLocation: CLLocation?, locations: inout [CLLocation]) -> CLLocationDistance {
if locations.isEmpty {
return initialDistance
} else if let initialLocation = initialLocation {
let firstLocation = locations.removeFirst()
let distance = firstLocation.distance(from: initialLocation)
return totalDistance(initialDistance: initialDistance + distance, initialLocation: firstLocation, locations: &locations)
}
return totalDistance(initialDistance: initialDistance, initialLocation: locations.removeFirst(), locations: &locations)
}
print(totalDistance(initialDistance: 0.0, initialLocation: nil, locations: &locations)) // Prints 33182.563139193335
/* REDUCE EXAMPLE */
print([2, 5, 3, 10].reduce(0, +)) // Prints 20
/* A REDUCED SOLUTION */
/// First closure example
let closure1: ((CLLocationDistance, CLLocation?), CLLocation) -> (CLLocationDistance, CLLocation?) = { tuple, location in
guard let previousLocation = tuple.1 else {
return (tuple.0, location)
}
return (tuple.0 + location.distance(from: previousLocation), location)
}
print(locations.reduce((0.0, nil), closure1).0) // Prints 33182.563139193335
/// Second closure example
let closure2: ((CLLocationDistance, CLLocation?), CLLocation) -> (CLLocationDistance, CLLocation) = { tuple, location in
return (tuple.0 + location.distance(from: tuple.1 ?? location), location)
}
print(locations.reduce((0.0, nil), closure).0) // Prints 33182.563139193335
/// The one-liner solution
func totalDistanceReduce(of locations: [CLLocation]) -> CLLocationDistance {
return locations.reduce((0.0, nil), { ($0.0 + $1.distance(from: $0.1 ?? $1), $1) }).0
}
print(totalDistanceReduce(of: locations)) // Prints 33182.563139193335
/* THE ICING ON THE CAKE */
extension Array where Element: CLLocation {
/// Returns the total distance of the list of CLLocation objects.
var totalDistance: CLLocationDistance {
return reduce((0.0, nil), { ($0.0 + $1.distance(from: $0.1 ?? $1), $1) }).0
}
}
print(locations.totalDistance) // Prints 33182.563139193335
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment