首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有4个可选字符串的对象?属性的加权值,如何将具有最佳匹配值的对象返回到一组属性。

具有4个可选字符串的对象?属性的加权值,如何将具有最佳匹配值的对象返回到一组属性。
EN

Stack Overflow用户
提问于 2018-05-30 22:15:36
回答 2查看 84关注 0票数 3

所以起初,这似乎是一个非常直截了当的问题,但我发现了一些小问题,而我目前的解决方案很难看,所以我很想知道你们能想出些什么来。

我有个课,OptionalObject。它有四个属性,

代码语言:javascript
复制
let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?

然后,我有了一个由1000个这样的OptionalObject对象组成的数组,并且保证没有两个具有完全相同属性的对象。

(OptionalObject: prop1,prop2,prop3,prop4

代码语言:javascript
复制
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个字符串(非可选)。

代码语言:javascript
复制
(ConcreteObject: arg1: String, arg2: String, arg3: String, arg4: String)

我想根据这四个属性找到最佳匹配的 OptionalObject和my ConcreteObject

我可以想到两种方法,一种是在所有OptionalObjects上使用OptionalObjects,另一种是在所有OptionalObjects上手动枚举,有嵌套的if语句来检查属性(这实际上与filter一样)

如果我要过滤,可能是这样的:

代码语言:javascript
复制
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能回来

那么,自然的,我想好,让我们先看看我们有哪些参数为非零,然后相应地构造一个查询。

对于本例,我将假设只有两个属性,因此更容易理解:

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
New1: nil, 999, nil, NiHao
New2: XYZ, 999, nil, nil

我们选择New2,因为尽管New1New2都有两个匹配属性,但New2具有更高权重的匹配属性。

所以,这是一个两难的问题。

我希望我只是不记得几年前在我的大学算法课上的一些关键概念,并且有一些干净的解决方案(也许是斯威夫特提供的东西),但是我的智慧已经接近尾声了--所以,任何有洞察力或见解的人都是受欢迎的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-30 23:15:39

这是一个合理的解决方案。有关详细信息,请参阅代码注释。

代码语言:javascript
复制
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中的第一个对象得分最高。

票数 1
EN

Stack Overflow用户

发布于 2018-05-30 23:15:31

数学,特别是基本代数,给出了答案。

您需要在您的OptionalObject实例上定义一个二进制关系,它是反对对称的、传递的,但不是connex。就像< for整数一样。

这是签名:

代码语言:javascript
复制
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)进行排序。

代码语言:javascript
复制
optionalObjectsArray.sort(by: myRelation)

最后,返回集合中的第一个对象是您正在寻找的对象:

代码语言:javascript
复制
let myBestMatch = OptionalObjectsArray.sort(by: myRelation).first()
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50614051

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档