我们正在尝试优化我们一直在使用的一些“加权”匹配算法,并决定咨询互联网以获得更多想法
我们有一个Struct MyStruct
,有5个可选属性(在swift中,这只意味着属性可以是nil
):
prop1: String?
prop2: String?
prop3: String?
prop4: String?
prop5: String?
然后我们有一组MyStruct
(保证没有2个实例具有相同的确切属性),
structArray: Set<MyStruct>
我们有一个函数,它接受这个数组,以及字典中的1-5个属性,返回1个最匹配的单个实例。如果任何属性不匹配,则实例立即退出竞争
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
}
例:
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)
在prop3上exInstance1只有1个匹配,但因为prop1根本不匹配,所以exInstance没有得分
exInstance2匹配两个属性,得分为20
exInstance3匹配一个属性,得分为4
选择并返回exInstance2
问题:有更好的方法吗?如果没有,有什么办法可以改进这个算法吗?
如果你将for循环外的字典访问分解出来,我只会看到一点点改进,例如:
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
}
在这种情况下,可以进行以下优化:
基于以上所述,我提出以下解决方案:
import Foundation
struct MyStruct {
var prop1: String? = nil
var prop2: String? = nil
var prop3: String? = nil
}
extension MyStruct: Hashable {}
func findBestMatch(for set: Set<MyStruct>,
oProperty1: String? = nil,
oProperty2: String? = nil,
oProperty3: String? = nil) -> MyStruct?
{
let mask000 = 0b00000000
let mask001 = 0b00000001
let mask010 = 0b00000010
let mask011 = 0b00000011
let mask100 = 0b00000100
let mask101 = 0b00000101
let mask110 = 0b00000110
let mask111 = 0b00000111
var mask = mask000
if let _ = oProperty1 {
mask |= mask001
}
if let _ = oProperty2 {
mask |= mask010
}
if let _ = oProperty3 {
mask |= mask100
}
if mask == mask000 {
return nil
} else if mask == mask001 {
let prop3 = oProperty3!
return set.first(where: { $0.prop3 == prop3 })
} else if mask == mask010 {
let prop2 = oProperty2!
return set.first(where: { $0.prop2 == prop2 })
} else if mask == mask011 {
let prop2 = oProperty2!
let prop3 = oProperty3!
return set.first(where: { $0.prop2 == prop2 && $0.prop3 == prop3 })
} else if mask == mask100 {
let prop1 = oProperty1!
return set.first(where: { $0.prop1 == prop1 })
} else if mask == mask101 {
let prop1 = oProperty1!
let prop3 = oProperty3!
return set.first(where: { $0.prop1 == prop1 && $0.prop3 == prop3 })
} else if mask == mask110 {
let prop1 = oProperty1!
let prop2 = oProperty2!
return set.first(where: { $0.prop1 == prop1 && $0.prop2 == prop2 })
} else if mask == mask111 {
let prop1 = oProperty1!
let prop2 = oProperty2!
let prop3 = oProperty3!
return set.first(where: { $0.prop1 == prop1 && $0.prop2 == prop2 && $0.prop3 == prop3 })
}
return nil
}
let exInstance1 = MyStruct(prop1: "no good", prop2: nil, prop3: "goodbye")
let exInstance2 = MyStruct(prop1: "hello", prop2: "noproblem", prop3: "goodbye")
let exInstance3 = MyStruct(prop1: nil, prop2: nil, prop3: "goodbye")
let exampleSet: Set<MyStruct> = [
exInstance1,
exInstance2,
exInstance3,
]
if let object = findBestMatch(for: exampleSet, oProperty1: "hello", oProperty2: nil, oProperty3: "goodbye") {
print(object) // print MyStruct(prop1: Optional("hello"), prop2: Optional("noproblem"), prop3: Optional("goodbye"))
} else {
print("not found")
}
我们将逐步分析您的示例:
mask = 000
oProperty1 != nil
。 => Qazxswpoimask = mask | 100 = 000 | 100 = 100
。 => QazxswpoioProperty2 == nil
。 => Qazxswpoimask = 100
。 =>
oProperty3 != nil