Search code examples
iosarraysswiftgoogle-places-apicontains

Determine whether array contains one or more elements of another array in swift


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.


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 }
        }
    }