所以起初,这似乎是一个非常直截了当的问题,但我发现了一些小问题,而我目前的解决方案很难看,所以我很想知道你们能想出些什么来。
我有个课,OptionalObject。它有四个属性,
let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?然后,我有了一个由1000个这样的OptionalObject对象组成的数组,并且保证没有两个具有完全相同属性的对象。
(OptionalObject: prop1,prop2,prop3,prop4
Obj1: ABC, 123, Hello, Goodbye
Obj2: DEF, 456, nil, nil
Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj5: ABC, nil, nil, nil
Obj6: ABC, nil, Hello, Goodbye
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil
...然后,我有另一个类的单数对象,它包含所有4个字符串(非可选)。
(ConcreteObject: arg1: String, arg2: String, arg3: String, arg4: String)我想根据这四个属性找到最佳匹配的 OptionalObject和my ConcreteObject。
我可以想到两种方法,一种是在所有OptionalObjects上使用OptionalObjects,另一种是在所有OptionalObjects上手动枚举,有嵌套的if语句来检查属性(这实际上与filter一样)
如果我要过滤,可能是这样的:
let matchingOptionalObject = optionalObjectsArray.filter {return $0.prop1 == arg1 && $0.prop2 == arg2 && $0.prop3 == arg3 && $0.prop4 == arg4}我现在有一个和.但前提是完全匹配。
如果我的ConcreteObject有(DEF, 123, Hello, Goodbye),我就不会得到任何匹配,因为没有完全匹配的OptionalObjects。
我希望Obj3, Obj4, Obj7, Obj8能回来
那么,自然的,我想好,让我们先看看我们有哪些参数为非零,然后相应地构造一个查询。
对于本例,我将假设只有两个属性,因此更容易理解:
let matchingOptionalObject = optionalObjectsArray.filter {
if $0.prop1 != nil {
if $0.prop2 != nil {
return $0.prop1 == arg1 && $0.prop2 == arg2
} else {
return $0.prop1 == arg1
}
} else {
if $0.prop2 != nil {
return $0.prop2 == arg2
} else {
return false
}
}
}但是问题是,因为有4个属性,我们需要讨论的惟一nil参数至少有10种不同的可能性,这就变得非常丑陋了。
这就是我目前所拥有的,我有一堆丑陋的if语句检查nil参数的组合,然后构造相应的filter查询.
好的,我们需要继续前进,所以我想我们可以解决这个问题,然后再找出一个更好的解决方案,但是还有一个要求使得这个解决方案不起作用。
每个属性都有不同的权重。
当有多个匹配时,选择最佳匹配的两个规则:
1)选择匹配属性最多的匹配项。
2)如果匹配的属性数量相同,则选择权重最高的匹配。
Prop1的重量最高
Prop2是最低的
因此,以ConcreteObject:(DEF, 123, Hello, Goodbye)为例
匹配OptionalObjects
Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil我们选择Obj7作为最佳匹配,因为它有3个匹配属性
但是,让我们以一个新的ConcreteObject和一组新的OptionalObjects为例,我们有这样的匹配:
我们的新匹配OptionalObjects
New1: nil, 999, nil, NiHao
New2: XYZ, 999, nil, nil我们选择New2,因为尽管New1和New2都有两个匹配属性,但New2具有更高权重的匹配属性。
所以,这是一个两难的问题。
我希望我只是不记得几年前在我的大学算法课上的一些关键概念,并且有一些干净的解决方案(也许是斯威夫特提供的东西),但是我的智慧已经接近尾声了--所以,任何有洞察力或见解的人都是受欢迎的。
发布于 2018-05-30 23:15:39
这是一个合理的解决方案。有关详细信息,请参阅代码注释。
struct OptionalObject {
let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?
}
struct ConcreteObject {
let prop1: String
let prop2: String
let prop3: String
let prop4: String
// Determine the score.
// "matches" counts the number of matching properties.
// "weight" gives 8 for the 1st property, 4 for the 2nd, 2 for the 3rd, 1 for the 4th. Adjust to suit your needs
func score(for opt: OptionalObject) -> (matches: Int, weight: Int) {
var matches = 0
var weight = 0
if opt.prop1 == self.prop1 { matches += 1; weight += 8 }
if opt.prop2 == self.prop2 { matches += 1; weight += 4 }
if opt.prop3 == self.prop3 { matches += 1; weight += 2 }
if opt.prop4 == self.prop4 { matches += 1; weight += 1 }
return (matches, weight)
}
// Compares two OptionalObject by getting the score of each
// against "self".
func compare(lhs: OptionalObject, rhs: OptionalObject) -> Bool {
let scoreL = score(for: lhs)
let scoreR = score(for: rhs)
// If the number of matches are the same, compare the weight
return scoreL > scoreR
}
}
// Test ConcreteObject
let concrete = ConcreteObject(prop1: "DEF", prop2: "123", prop3: "Hello", prop4: "Goodbye")
// List of OptionalObject
var optionals: [OptionalObject] = [
OptionalObject(prop1: nil, prop2: nil, prop3: "Hello", prop4: nil),
OptionalObject(prop1: "DEF", prop2: "456", prop3: nil, prop4: nil),
OptionalObject(prop1: "ABC", prop2: "123", prop3: "Hello", prop4: "Goodbye"),
OptionalObject(prop1: nil, prop2: nil, prop3: "Hello", prop4: "Goodbye"),
OptionalObject(prop1: "DEF", prop2: "456", prop3: "Hello", prop4: "Goodbye"),
//OptionalObject(prop1: nil, prop2: nil, prop3: nil, prop4: nil),
]
// Sort the list based on the ConcreteObject
let sorted = optionals.sorted { concrete.compare(lhs: $0, rhs: $1) }
print(sorted)结果按所需的顺序排序。sorted中的第一个对象得分最高。
发布于 2018-05-30 23:15:31
数学,特别是基本代数,给出了答案。
您需要在您的OptionalObject实例上定义一个二进制关系,它是反对对称的、传递的,但不是connex。就像< for整数一样。
这是签名:
func myRelation(_ o1: OptionalObject, _ o2: OptionalObject) -> Bool {
// compare the 4 member properties of o1 and o2, using weights if not nil
// return true if o1 matches best, otherwise return false
}在您的问题中,您已经指定了需要在此函数中实现的规则。但是请注意,如果规则没有导致反对称的、传递的而不是connex二进制关系,那么您的问题就没有得到很好的定义:从数学上讲,您需要有定义总顺序的规则,这样才能得到一个可用的解决方案。
现在,您的一组OptionalObject实例必须使用Swift标准的func排序(by:(Element,Element) -> Bool)进行排序。
optionalObjectsArray.sort(by: myRelation)最后,返回集合中的第一个对象是您正在寻找的对象:
let myBestMatch = OptionalObjectsArray.sort(by: myRelation).first()https://stackoverflow.com/questions/50614051
复制相似问题