2017-10-10 9 views
0

Je le code suivant qui retourne des endroits près de l'emplacement actuel de l'utilisateurDéterminer si un tableau contient un ou plusieurs éléments d'un autre tableau dans rapide

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 dans ma fonction de rappel au bas retourne un tableau de chaînes pour chaque instance de lieu, ce qui ressemble à ceci:

["health", "point_of_interest", "establishment"]

J'ai un tableau global de chaînes qui contient également des balises telles que bakery,Lorsque l'utilisateur appuie sur un bouton, la fonction de rappel est déclenchée et renvoie des lieux en fonction de l'emplacement à proximité.

La sortie ressemble à ceci:

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 

Le même établissement est répétée plusieurs fois parce qu'un établissement unique a plus d'une étiquette qui lui est associée.

Par exemple:

Le tableau retourné pour place.types pour LOCAL TAKEAWAY est: ["meal_takeaway", "restaurant", "food"]

et parce que mon tableau GlobalVariables.acceptedEstablishments contient tous les trois de ces chaînes, la commande print sera exécutée trois fois.

Comment ce code peut-il être modifié afin qu'il n'affiche l'établissement qu'une seule fois, si le tableau place.types contient une ou plusieurs des chaînes correspondantes? Je n'arrive pas à trouver une solution.

+0

NSSet? NSSet où êtes-vous? Veuillez utiliser NSSet –

+0

@Gagan_iOS Je ne suis pas sûr de ce que c'est. Pouvez-vous me fournir un exemple de comment utiliser NSSet/à quoi cela sert-il? Je suppose qu'il a quelque chose à voir avec les tableaux, mais la documentation Array sur le site Web d'Apple ne mentionne rien à ce sujet: https://developer.apple.com/documentation/swift/array Merci d'avance. Je suis nouveau à Swift mais cherche toujours à apprendre –

+1

Regardez cette réponse https://stackoverflow.com/questions/32439289/how-to-get-list-of-common-elements-of-2-array-in- swift mieux que NSSet. NSSet permet d'obtenir des objets communs de deux collections. –

Répondre

1

La classe Swift Array permet la duplication d'éléments. La classe Set ne l'est pas. Vous pouvez créer une extension sur Array qui possède une méthode uniqueItems qui supprime les doublons. Notez que les éléments du tableau doivent être Hashable pour que cela fonctionne.

Ci-dessous l'extension. (Mon code - prise de another SO post)

extension Array where Element: Hashable { 
    var uniqueItems: Array { 
     var set = Set<Element>() 
     return flatMap { set.insert($0).inserted ? $0 : nil } 
    } 
} 
1

La clé utilise Set qui n'aura pas de doublons. Set est une classe de collection qui peut être utilisée de la même manière que les tableaux. Vous pouvez parcourir, et il a count, map, filter, contains, etc.

let acceptedPlaces: Set = ["home", "pub", "hospital"] 
let availablePlaces: Set = ["home", "pub", "mountains"] 
let inBoth = acceptedPlaces.intersection(availablePlaces) // ["home", "pub"] 

Vous pouvez facilement créer Set s de Array s let someSet = Set(someArray) et l'inverse let someArray = Array(someSet). Vous pouvez également jeter un oeil aux fonctions suivantes de Set: union, substract, isSuperSet, isSubset.

2

Vous pouvez également utiliser des ensembles:

if !Set(place.types).intersection(GlobalVariables.acceptedEstablishments).isEmpty 
{ 
    // there is at least one common element 
} 

Si vous pouvez vous permettre de faire GlobalVariables.acceptedEstablishments un ensemble, la condition serait plus efficace et pourrait être écrit:

if !GlobalVariables.acceptedEstablishments.intersection(places.types).isEmpty 
{ 
    // there is at least one common element 
} 

Dans les deux cas places.types n'a pas besoin d'être un ensemble lui-même.