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
})
CodePudding user response:
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)
})
CodePudding user response:
The problem is that userProfile.interests
is an array itself. Based on your example and expected output of John and Harry, it seems what you are actually trying to achieve is to keep the users who have at least 1 matching interest compared to your preferenceInterests
input.
To achieve that, you need to change the body of your filter
and use contains(where:)
instead of contains
to check if there is a match in interests.
let filteredUsers = userProfiles.filter { userProfile in
preferenceInterests.contains(where: { interest in userProfile.interests.contains(interest) })
}