简体   繁体   English

判断数组是否包含swift中另一个数组的一个或多个元素

[英]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:我底部回调place.types中的 place.types 为每个地点实例返回一个字符串数组,看起来像这样:

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

I have a global array of strings which also contains tags such as bakery , bar , etc.我有一个全局字符串数组,其中还包含诸如bakerybar等标签。

When the user presses a button, the callback function is triggered and returns places based on the nearby location.当用户按下按钮时,会触发回调 function 并根据附近位置返回地点。

The output looks something like this: output 看起来像这样:

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"] LOCAL TAKEAWAYplace.types返回的数组是: ["meal_takeaway", "restaurant", "food"]

and because my GlobalVariables.acceptedEstablishments array contains all three of those strings, the print command will be executed three times.因为我的GlobalVariables.acceptedEstablishments数组包含所有这三个字符串, print命令将被执行三次。

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?如果place.types数组包含一个或多个匹配字符串,如何修改此代码以使其仅显示一次机构? I can't seem to get my head around a solution.我似乎无法找到解决方案。

You could also use sets: 您还可以使用集合:

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

If you can afford to make GlobalVariables.acceptedEstablishments a Set, then the condition would be more efficient and could be written as : 如果您有能力将GlobalVariables.acceptedFoundations设置为Set,则该条件将更有效,可以写为:

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

In either cases places.types does not need to be a set itself. 在这两种情况下,places.types本身都不必是集合。

The Swift Array class allows duplicate items. Swift Array类允许重复项。 The Set class does not. Set类没有。 You can create an extension on Array that has a method uniqueItems that strips away duplicates. 您可以在Array上创建一个扩展,该扩展具有一个方法uniqueItems来去除重复项。 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 ) (不是我的代码-摘自另一个SO帖子

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

The key is using Set which will not have duplicates. 关键是使用Set ,它将没有重复项。 Set is a collection class which can be used similarly to arrays. Set是一个集合类,可以类似于数组使用。 You can iterate over it, and it has count , map , filter , contains , etc. 您可以对其进行迭代,并且它具有countmapfiltercontains等。

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

You can easily create Set s from Array s let someSet = Set(someArray) and the other way round let someArray = Array(someSet) . 您可以从Array轻松创建Setlet someSet = Set(someArray)let someSet = Set(someArray)let someArray = Array(someSet) You might also want to take a look at the following functions of Set : union , substract , isSuperSet , isSubset . 你可能也想看看以下功能SetunionsubstractisSuperSetisSubset

Using isDisjoint(with:) :使用isDisjoint(with:)

if !Set(place.types).isDisjoint(GlobalVariables.acceptedEstablishments) {
    // There is at least one common element
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM