Search code examples
arraysswiftfiltercontains

Swift filter an array inside a struct by another array


I've got an array of Profile's (defined from a custom struct), and inside this, I have a [String] of interests.

I want to filter out any profiles which don't match an array of preferences, but can't seem to get my filtering to work.

The error I get is

"Cannot convert value of type '[String]' to expected argument type 'String'.

What am I missing?

Once complete, I'd expect userProfiles to contain only John and Harry.

struct Profile {
    var name: String
    var interests: [String]
}


var userProfiles: [Profile] = [
    Profile(name: "John", interests: ["Basketball", "Football", "Rowing"]),
    Profile(name: "Andrew", interests: ["Cycling", "Swimming", "Boxing"]),
    Profile(name: "Harry", interests: ["Hockey", "Baseball"])
]


let preferenceInterests = ["Basketball", "Hockey"]


userProfiles = userProfiles.filter({ (userProfile) -> Bool in
    print("\(userProfile.name): \(userProfile.interests)")
    return preferenceInterests.contains(userProfile.interests) //error here
})

Solution

  • Your problem is that userProfile.interests is an array, so it wouldn't be the element of preferencesInterests which contains String.

    If you think about it, you are trying to see if two sets of interests have anything in common. This is Set intersection. Sets are more efficient for this purpose than arrays because checking inclusion is O(1) instead of O(n).

    By making preferenceIntests into a Set<String> you can use .isDisjoint(with:) to see if there are any interests in common. As soon as Swift finds a single interest in common, it will return false because the sets contain a common element and are not disjoint. You'll want to invert that since you want a common interest to return true:

    let preferenceInterests: Set = ["Basketball", "Hockey"]
    
    userProfiles = userProfiles.filter({ (userProfile) -> Bool in
        print("\(userProfile.name): \(userProfile.interests)")
        return !preferenceInterests.isDisjoint(with: userProfile.interests)
    })