Last active
September 12, 2015 19:10
-
-
Save manmal/a5d3ee15bf5ed65ddecc to your computer and use it in GitHub Desktop.
Functional Nerdgasm in Swift
This file contains hidden or 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
| typealias DistanceRange = (from: Double, to: Double) // meters | |
| typealias WaterListResult = (water: Water, lodging: Lodging, distance: Double, price: Float?) | |
| typealias LodgingAndDistance = (lodging: Lodging, distance: Double?) | |
| extension Water { | |
| // Returns waters that are sorted by their nearest (nearest to `center`) lodging's distance to `center`. | |
| static func watersByProximity(distanceRange: DistanceRange, center: CLLocation) -> [WaterListResult] { | |
| return ModelsStorage.waters | |
| .flatMap { (water: Water) -> [WaterListResult] in // Map to water's lodgings combined with their distances to center | |
| if let lodgings = water.lodgings { | |
| let lodgingAndDistance = lodgings | |
| .map { return LodgingAndDistance($0, $0.coordinates?.distanceTo(center)) } // attach distances to lodgings | |
| .filter { return $0.1 != nil } // filter those with non-nil distance | |
| .map { (lD: LodgingAndDistance) -> LodgingAndDistance in // force-unwrap filtered non-nil distances | |
| return LodgingAndDistance(lD.lodging, lD.distance!) | |
| } | |
| .filter { (lD: LodgingAndDistance) -> Bool in // filter those that are within distanceRange | |
| return lD.distance >= distanceRange.from && lD.distance < distanceRange.to | |
| } | |
| .sort({ $0.distance < $1.distance }) // sort lodgings of this water by distance | |
| .first // select only first lodging | |
| if let foundLodgingAndDistance = lodgingAndDistance { | |
| return [WaterListResult(water: water, lodging: foundLodgingAndDistance.lodging, distance: foundLodgingAndDistance.distance!, price: nil)] | |
| } | |
| } | |
| return [] // found no lodgings for this water | |
| } | |
| .sort({ $0.distance < $1.distance }) // sort ALL lodgings by their distance | |
| } | |
| } |
if the lodgings property of the Water struct is [Lodging] instead of [Lodging]? it gets down to:
extension Water {
// Returns waters that are sorted by their nearest (nearest to `center`) lodging's distance to `center`.
static func watersByProximity(distanceRange: DistanceRange, center: CLLocation) -> [WaterListResult] {
return ModelsStorage.waters
.flatMap { water -> [WaterListResult] in // Map to water's lodgings combined with their distances to center
let lodgingAndDistance = water.lodgings
.flatMap { LodgingAndDistance(lodging: $0, distance: $0.coordinates?.distanceTo(center)) } // attach distances to lodgings and filter out nils
.filter { $0.distance >= distanceRange.from && $0.distance < distanceRange.to } // filter those that are within distanceRange
.sort { $0.distance < $1.distance } // sort lodgings of this water by distance
.first // select only first lodging
return lodgingAndDistance.map { [WaterListResult(water: water, lodging: $0.lodging, distance: $0.distance, price: nil)] } ?? []
}
.sort { $0.distance < $1.distance } // sort ALL lodgings by their distance
}
}I'm not sure why you're getting the first lodgingAndDistance then mapping into into an array of WaterListResults, I'm assuming you don't actually want that. If you don't you can get it down to:
extension Water {
// Returns waters that are sorted by their nearest (nearest to `center`) lodging's distance to `center`.
static func watersByProximity(distanceRange: DistanceRange, center: CLLocation) -> [WaterListResult] {
return ModelsStorage.waters
.flatMap { water in
let results = water.lodgings
.flatMap { LodgingAndDistance(lodging: $0, distance: $0.coordinates?.distanceTo(center)) } // attach distances to lodgings, filtering out nils
.filter { $0.distance >= distanceRange.from && $0.distance < distanceRange.to } // filter those that are within distanceRange
.sort { $0.distance < $1.distance } // sort lodgings of this water by distance
.first // select only first lodging
.map { WaterListResult(water: water, lodging: $0.lodging, distance: $0.distance, price: nil) }
return results
}
.sort { $0.distance < $1.distance } // sort ALL WaterListResults by their distance
}
}Have to assign the results thing because otherwise swift thinks the expression is too complex
another option is this;
extension Water {
// Returns waters that are sorted by their nearest (nearest to `center`) lodging's distance to `center`.
static func watersByProximity(distanceRange: DistanceRange, center: CLLocation) -> [WaterListResult] {
let toResults = { water in
return water.lodgings
.flatMap { LodgingAndDistance(lodging: $0, distance: $0.coordinates?.distanceTo(center)) } // attach distances to lodgings, filtering out nils
.filter { $0.distance >= distanceRange.from && $0.distance < distanceRange.to } // filter those that are within distanceRange
.sort { $0.distance < $1.distance } // sort lodgings of this water by distance
.first // select only first lodging
.map { WaterListResult(water: water, lodging: $0.lodging, distance: $0.distance, price: nil) }
}
return ModelsStorage.waters.flatMap(toResults).sort { $0.distance < $1.distance } // sort ALL WaterListResults by their distance
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is all assuming your models look something like: