0

I have the following array which is loaded up with businesses:

var businessesArray = [Business]()

Now each Business has a latitude and longitude attribute:

private var _latitude: Double
private var _longitude: Double

What is the most efficient way (using swift) to sort businessesArray by putting business closest to the user at the start and farthest from the user at the end (sorted from nearest to farthest)? Assume I already have the user's current location in these variables:

var currentUserLatitude: Double
var currentUserLongitude: Double
Jason Fel
  • 921
  • 4
  • 10
  • 29

3 Answers3

4

Given this struct (you can also use a class)

struct Business {
    let latitude: Double
    let longitude: Double

    var location: CLLocation {
        return CLLocation(latitude: latitude, longitude: longitude)
    }
}

The user location

var currentUserLatitude: Double = ...
var currentUserLongitude: Double = ...
let userLocaton = CLLocation(
    latitude: currentUserLatitude,
    longitude: currentUserLongitude
)

And a list of places

let places: [Business] = ...

This is how you sort them

let sortedPlaces = places.sort {
    userLocaton.distanceFromLocation($0.0.location) < userLocaton.distanceFromLocation($0.1.location)
}

Or if you prefer the extended notation code

let sortedPlaces = places.sort { (left, right) -> Bool in
    userLocaton.distanceFromLocation(left.location) < userLocaton.distanceFromLocation(right.location)
}

How does it work?

The sort method accepts a closure.

Inside this closure you must specify the sorting logic. More specifically, given 2 Business values left and right, if left should be placed before right in the final sorting then the closure returns true. Otherwise false.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    Man, swift makes everything too easy haha! – Sethmr Jul 02 '16 at 21:18
  • If you don't mind can you explain what is happening in the last line:"userLocaton.distanceFromLocation($0.0.location) < userLocaton.distanceFromLocation($0.1.location"? What are the weird numbers like $0.0.location doing? – Jason Fel Jul 02 '16 at 21:25
  • @JasonFel: I updated my code to make it easier. I also added a final explanation. Please check it out. – Luca Angeletti Jul 02 '16 at 21:34
  • Hmmm. Just curious how would I sort by business name? I assume it is something even simpler. My business also has a "name" variable. – Jason Fel Jul 02 '16 at 22:47
  • @JasonFel: `let sorted = places.sort { (left, right) -> Bool in left.name < right.name }` – Luca Angeletti Jul 02 '16 at 22:50
1

You can use the CLLocation class and it's distanceFromLocation method to calculate the distances from the current location.

Extending the Business model

extension Business {
    var location: CLLocation {
        return CLLocation(latitude: self.latitude, longitude: self.longitude)
    }
}

Sorting the places array

let userLocaton = CLLocation(latitude: currentUserLatitude, longitude: currentUserLongitude)

let sortedPlaces = places.sort { (left, right) -> Bool in 
  userLocation.distanceFromLocation(left.location) < userLocation.distanceFromLocation(right.location))
}
itskoBits
  • 435
  • 4
  • 13
0

Inside Business create a computed variable like so

var distanceFromUser: Double {
    return pow((userLat - _latitude), 2) + pow((userLon - _longitude), 2)
}

then where you have your array of Businesses call

businessesArray.sort({ $0.distanceFromUser < $1.distanceFromUser})

I know the earth isn't flat, but Pythagorean Theorem still works as intended. You never need to take the square root, because obviously if a > b then sqrt(a) > sqrt(b), and you don't have to take the abs because squaring them does it for you :)

Sethmr
  • 3,046
  • 1
  • 24
  • 42