swift - 具有 4 个可选字符串的对象?具有加权值的属性,如何返回与一组属性最匹配的对象

标签 swift algorithm match matching

所以起初这似乎是一个非常直接的问题来解决,但我发现了一些小问题,而且我目前的最终解决方案非常丑陋,所以我很想知道你们能想出什么与

我有一个类,OptionalObject。 它有四个属性,

let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?

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

EX: (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 到我的ConcreteObject

我可以想到两种方法,一种是对所有OptionalObjects使用filter,另一种是手动枚举所有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


所以我自然而然地认为 OK,让我们首先看看我们有哪些参数是非 nil,然后相应地构造一个查询。

对于这个例子,我假设只有两个属性,这样更容易理解:

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 个属性,所以我们需要覆盖至少 10 种不同的唯一 nil 参数,这变得非常丑陋

这就是我目前所拥有的,我有一堆丑陋的 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,因为即使 New1New2 都有 2 个匹配属性,New2 有更高权重的匹配属性。


所以,问题来了。
我希望我只是不记得几年前在我的本科算法课上的一些关键概念,并且有一些干净的解决方案(甚至可能是 Swift 提供的东西),但我已经快要穷尽了——所以真的任何人的建议或见解都非常受欢迎

最佳答案

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

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 中的第一个对象得分最高。

关于swift - 具有 4 个可选字符串的对象?具有加权值的属性,如何返回与一组属性最匹配的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50614051/

相关文章:

javascript - 替换所有非单词字符,如 ?*+#

ios7 - 快速关闭模态视图 Controller 后的 Popview

Javascript/正则表达式 : Lookbehind Assertion is causing a "Invalid group" error

ios - IPA 文件结构 - SupportSwift & Symbols

algorithm - 什么是自然密集图的例子?

python - NetworkX 多向图可能吗?

c - 递归 FloodFill 算法的段错误

iOS - NSString 正则表达式匹配

Swift:锁匠不更新数据

ios - Sprite Kit SKAction 组暂停应用程序