Edison
Edison

Reputation: 11987

filter/identify dictionary keys that have matching values

Not sure if I need reduce, sorting, filtering or using the newer unique methods. I've even tried Equatable solutions.

I need to auto-identify keys that have matching values and take only those keys and put them into a new dictionary or array.

var userDB: [String:Any] = ["userID1":"gameIDa", "userID2":"gameIDa", "userID3":"gameIDc", "userID4":"gameIDd", "userID5":"gameIDe"]


As you can see only these two IDs have the same value of gameIDa. I need output of this result.

// [userID1, userID2]

Thanks

Upvotes: 1

Views: 71

Answers (2)

Cristik
Cristik

Reputation: 32904

Firstly, in order to be able to compare values, the Dictionary Value type needs to be an Equatable one. Once this is fulfilled, you can easily filter the keys that hold the queried value:

extension Dictionary where Value: Equatable {
    func keysWithCommonValues() -> [Key] {
        // go over all keys and keep ones for which the dictionary has one another key with the same value
        return keys.filter { key in contains { $0.key != key && $0.value == self[key] } }
    }
}

// userDB is not inferred as [String:String]
var userDB = ["userID1":"gameIDa", "userID2":"gameIDa", "userID3":"gameIDc", "userID4":"gameIDd", "userID5":"gameIDe"]
print(userDB.keysWithCommonValues()) // ["userID1", "userID2"]

Upvotes: 1

Rakesha Shastri
Rakesha Shastri

Reputation: 11242

You can use Dictionary(grouping:by:) to achieve this easily and then reduce it to a dictionary which contains only entries with multiple values.

var userDB: [String: String] = ["userID1":"gameIDa", "userID2":"gameIDb", "userID3":"gameIDc", "userID4":"gameIDa", "userID5":"gameIDe"]

let dict = Dictionary(grouping: userDB.keys) { userDB[$0] ?? "" }.reduce(into: [String:[String]](), { (result, element) in
    if element.value.count > 1 {
        result[element.key] = element.value
    }
})

dict

["gameIDa": ["userID1", "userID4"]]

Upvotes: 2

Related Questions