I have the following code which returns places near the user's current location
import UIKit
import GooglePlaces
import CoreLocation
struct GlobalVariables {
static var acceptedEstablishments = ["bakery", "bar", "cafe", "food", "meal_takeaway", "meal_delivery", "night_club", "restaurant", "school", "university"]
}
class ViewController: UIViewController, CLLocationManagerDelegate {
var placesClient: GMSPlacesClient!
var locationManager: CLLocationManager!
// Add a pair of UILabels in Interface Builder, and connect the outlets to these variables.
@IBOutlet var nameLabel: UILabel!
@IBOutlet var addressLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
placesClient = GMSPlacesClient.shared()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
// Add a UIButton in Interface Builder, and connect the action to this function.
@IBAction func getCurrentPlace(_ sender: UIButton) {
placesClient.currentPlace(callback: { (placeLikelihoodList, error) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
if let placeLikelihoodList = placeLikelihoodList {
for likelihood in placeLikelihoodList.likelihoods {
let place = likelihood.place
// only return places that are relevant to me
for placeType in place.types {
if (GlobalVariables.acceptedEstablishments.contains(placeType)) {
print("Current place name: \(place.name)")
print("Place type: \(placeType)")
}
}
}
}
})
}
}
place.types
in my callback function at the bottom returns an array of strings for each place instance, which looks something like this:
["health", "point_of_interest", "establishment"]
I have a global array of strings which also contains tags such as bakery
, bar
, etc.
When the user presses a button, the callback function is triggered and returns places based on the nearby location.
The output looks something like this:
Current place name: LOCAL SUPERMARKET
Place type: food
Current place name: LOCAL GRILL
Place type: cafe
Current place name: LOCAL GRILL
Place type: food
Current place name: LOCAL SCHOOL
Place type: school
Current place name: LOCAL TAKEAWAY
Place type: meal_takeaway
Current place name: LOCAL TAKEAWAY
Place type: restaurant
Current place name: LOCAL TAKEAWAY
Place type: food
The same establishment is repeated multiple times because a single establishment has more than one tag associated with it.
For example:
The returned array for place.types
for LOCAL TAKEAWAY
is: ["meal_takeaway", "restaurant", "food"]
and because my GlobalVariables.acceptedEstablishments
array contains all three of those strings, the print
command will be executed three times.
How can this code be amended so that it only displays the establishment once, if the place.types
array contains one or more of the matching strings? I can't seem to get my head around a solution.
The Swift Array class allows duplicate items. The Set class does not. You can create an extension on Array that has a method uniqueItems that strips away duplicates. Note that the items in the array have to be Hashable in order for this to work.
Below is the extension. (Not my code - taken from another SO post)
extension Array where Element: Hashable {
var uniqueItems: Array {
var set = Set<Element>()
return flatMap { set.insert($0).inserted ? $0 : nil }
}
}