We're trying to optimize some "weighted" matching algorithm we've been using, and decided to consult the internet for some more ideas
We have a Struct MyStruct
, with 5 optional properties (in swift, this just means that the property can be nil
):
prop1: String?
prop2: String?
prop3: String?
prop4: String?
prop5: String?
then we have an set of MyStruct
(guaranteed that there aren't 2 instances that have the same exact properties),
structArray: Set<MyStruct>
we have a function that takes this array, as well as the 1-5 properties in a dictionary, to return 1 single instance that best matches. If any of the properties don't match, the instance is taken out of contention immediately
func findBestMatch(forSet set:Set<MyStruct>, andArgs argDict:[String:String]) -> MyStruct? {
//Will use this to store any matches, as well as an associated match score
var bestMatch: MyStruct?
var topScore = 0
for element in set {
var score = 0
if let p1 = argDict["p1"] {
if p1 == element.prop1 {
score += 16 //p1 match has highest weight
} else {
continue
}
}
if let p2 = argDict["p2"] {
if p2 == element.prop2 {
score += 8 //p2 match has second-highest weight
} else {
continue
}
}
//etc for the other 3 properties
if score > topScore {
topScore = score
bestMatch = element
}
}
return bestMatch
}
EXAMPLE:
exInstance1
prop1 = "no good"
prop2 = nil
prop3 = "goodbye
exInstance2
prop1 = "hello"
prop2 = "noproblem"
prop3 = "goodbye"
exInstance3
prop1 = nil
prop2 = nil
prop3 = "goodbye"
exampleSet: Set<MyStruct> = [exInstance1, exInstance2, exInstance3]
matchingProperties: [String:String] = {
"p1": "hello",
"p3": "goodbye"
}
findBestMatch(forSet: exampleSet, andArgs: matchingProperties)
exInstance1 only has 1 match, on prop3, but because prop1 doesn't match at all, exInstance is not given a score
exInstance2 matches on both properties, and is given a score of 20
exInstance3 matches on one property, and is given a score of 4
exInstance2 is chosen and returned
Question: Is there a better way to do this? If not, are there any ways we could improve this algorithm?
I would only see a slight improvement if you factor out the dictionary accesses outside the for loop, e.g.
func findBestMatch(forSet set:Set<MyStruct>, andArgs argDict:[String:String]) -> MyStruct? {
//Will use this to store any matches, as well as an associated match score
var bestMatch: MyStruct?
var topScore = 0
let p1 = argDict["p1"]
let p2 = argDict["p2"] // and so on
for element in set {
var score = 0
if let p1 = p1 {
if p1 == element.prop1 {
score += 16 //p1 match has highest weight
} else {
continue
}
}
//etc for the other properties
if score > topScore {
topScore = score
bestMatch = element
}
}
return bestMatch
}