Last active
December 9, 2021 03:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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