Swift 一组具有可选字符串属性的对象,改进了接受字符串参数的函数,并在集合中找到最佳匹配
我们正在尝试优化一些我们一直使用的“加权”匹配算法,并决定参考互联网上的更多想法 我们有一个StructSwift 一组具有可选字符串属性的对象,改进了接受字符串参数的函数,并在集合中找到最佳匹配,swift,algorithm,pattern-matching,string-matching,Swift,Algorithm,Pattern Matching,String Matching,我们正在尝试优化一些我们一直使用的“加权”匹配算法,并决定参考互联网上的更多想法 我们有一个StructMyStruct,有5个可选属性(在swift中,这仅仅意味着属性可以是nil): 然后我们有一组MyStruct(保证没有两个实例具有相同的确切属性) structArray:Set 我们有一个函数,它接受这个数组以及字典中的1-5个属性,以返回一个最匹配的实例。如果任何属性不匹配,实例将立即退出争用 func findBestMatch(forSet set:Set<MyStruct
MyStruct
,有5个可选属性(在swift中,这仅仅意味着属性可以是nil
):
然后我们有一组MyStruct
(保证没有两个实例具有相同的确切属性)
structArray:Set
我们有一个函数,它接受这个数组以及字典中的1-5个属性,以返回一个最匹配的实例。如果任何属性不匹配,实例将立即退出争用
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
}
func findBestMatch(用于set:set和args argDict:[String:String])->MyStruct?{
//将使用此存储任何匹配项以及关联的匹配分数
var bestMatch:MyStruct?
var topScore=0
对于集合中的元素{
风险值得分=0
如果让p1=argDict[“p1”]{
如果p1==element.prop1{
分数+=16//p1匹配具有最高权重
}否则{
持续
}
}
如果让p2=argDict[“p2”]{
如果p2==element.prop2{
分数+=8//p2匹配具有第二高的权重
}否则{
持续
}
}
//其他3个属性的等
如果得分>topScore{
上核=得分
最佳匹配=元素
}
}
返回最佳匹配
}
示例:
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
prop1=“不好”
prop2=零
prop3=“再见
存在2
prop1=“你好”
prop2=“无问题”
prop3=“再见”
存在3
prop1=零
prop2=零
prop3=“再见”
exampleSet:Set=[exInstance1、exInstance2、exInstance3]
matchingProperties:[字符串:字符串]={
“p1”:“你好”,
“p3”:“再见”
}
findBestMatch(例如集合:exampleSet和Args:matchingProperties)
Existance 1在prop3上只有1个匹配项,但由于prop1根本不匹配,Existance不会得到分数
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
}
func findBestMatch(用于set:set和args argDict:[String:String])->MyStruct{
//将使用此存储任何匹配项以及关联的匹配分数
var bestMatch:MyStruct?
var topScore=0
设p1=argDict[“p1”]
设p2=argDict[“p2”]//以此类推
对于集合中的元素{
风险值得分=0
如果让p1=p1{
如果p1==element.prop1{
分数+=16//p1匹配具有最高权重
}否则{
持续
}
}
//其他物业等
如果得分>topScore{
上核=得分
最佳匹配=元素
}
}
返回最佳匹配
}
如果将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
}
func findBestMatch(用于set:set和args argDict:[String:String])->MyStruct{
//将使用此存储任何匹配项以及关联的匹配分数
var bestMatch:MyStruct?
var topScore=0
设p1=argDict[“p1”]
设p2=argDict[“p2”]//以此类推
对于集合中的元素{
风险值得分=0
如果让p1=p1{
如果p1==element.prop1{
分数+=16//p1匹配具有最高权重
}否则{
持续
}
}
//其他物业等
如果得分>topScore{
上核=得分
最佳匹配=元素
}
}
返回最佳匹配
}
在这种情况下,可以进行以下优化:
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")
}
在这种情况下,可以进行以下优化:
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")
}