Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 具有4个可选字符串的对象?具有加权值的属性,如何返回与一组属性最匹配的对象_Swift_Algorithm_Match_Matching - Fatal编程技术网

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

Swift 具有4个可选字符串的对象?具有加权值的属性,如何返回与一组属性最匹配的对象,swift,algorithm,match,matching,Swift,Algorithm,Match,Matching,所以一开始这似乎是一个非常直截了当的问题,但我发现了一些小问题,我目前的最终解决方案非常难看,所以我很好奇你们能想出什么 我有一个类,OptionalObject。 它有四个属性 let prop1: String? let prop2: String? let prop3: String? let prop4: String? 然后我有一个由一千个OptionalObject对象组成的数组,我保证没有两个对象具有完全相同的属性 例:(可选对象:prop1、prop2、prop3、prop4)

所以一开始这似乎是一个非常直截了当的问题,但我发现了一些小问题,我目前的最终解决方案非常难看,所以我很好奇你们能想出什么

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

let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?
然后我有一个由一千个
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个字符串(非可选)

我想根据这四个属性找到与我的
具体对象
最匹配的OptionalObject

我可以想到两种方法,一种是对所有
可选对象
使用
filter
,另一种是手动枚举所有
可选对象
,使用嵌套的
if
语句检查属性(实际上与
filter
相同)

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

let matchingOptionalObject = optionalObjectsArray.filter {return $0.prop1 == arg1 && $0.prop2 == arg2 && $0.prop3 == arg3 && $0.prop4 == arg4}
我现在有了一个匹配的物体,但前提是它是精确匹配的

如果我的
ConcreteObject
(DEF,123,你好,再见)
我不会得到任何匹配,因为没有任何
OptionalObjects
完全匹配

我希望返回
Obj3、Obj4、Obj7、Obj8


那么自然地我想好了,让我们先看看哪些参数是非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个属性,所以我们需要讨论的唯一
nil
参数至少有10种不同的可能性,这真的很难看

这就是我目前拥有的,我有一堆丑陋的
if
语句检查
nil
参数的组合,然后相应地构造一个
过滤器
查询


好吧,我们需要继续前进,所以我想我们可以解决这个问题,并在以后找到更好的解决方案,但还有一个要求使得这个解决方案不起作用

每个属性都有不同的权重

有多个匹配项时选择最佳匹配项的两条规则:
1) 选择具有最多匹配属性的匹配项
2) 如果匹配的属性数与匹配的属性数相同,请选择权重最高的匹配项

Prop1的重量最高
Prop2的性能最低

ConcreteObject
为例:
(DEF,123,Hello,再见)

匹配的
可选对象

Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil
New1: nil, 999, nil, NiHao
New2: XYZ, 999, nil, nil
我们会选择
Obj7
作为最佳匹配,因为它有3个匹配属性


但是,让我们举一个新的
ConcreteObject
和一组新的
OptionalObjects
的例子,我们有以下匹配:

我们新匹配的
OptionalObjects

Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil
New1: nil, 999, nil, NiHao
New2: XYZ, 999, nil, nil
我们会选择
New2
,因为尽管
New1
New2
都有两个匹配属性,
New2
具有更高权重的匹配属性


因此,这是一个两难的问题。

我希望几年前在我的本科算法课上,我没有记住一些关键概念,有一些干净的解决方案(甚至可能是斯威夫特提供的),但我已经快智穷了——所以任何人的任何建议或见解都是非常受欢迎的

数学,特别是基础代数,给你答案

您需要在OptionalObject实例上定义一个二进制关系,它是反对称的,可传递的,但不是connex。比如整数

签名如下:

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()

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

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)

结果按所需顺序排序。
排序中的第一个对象得分最高。

哇,太快了,很高兴看到你还活着——几年前我非常活跃的时候,我到处都能看到你。谢谢你的回答,我现在要试试:)很漂亮,很容易实现,而且是一个有效的解决方案。谢谢,我建议使用reduce而不是sort。Reduce将为您提供一个n阶解决方案,排序是order n log n。您只需
返回scoreL>scoreL
在比较函数中,元组(可比较元素)本身是可比较的。您还可以直接将可选值与非可选值进行比较:
如果opt.prop1==self.prop1{…}
等等。我相信,因为OptionalObjects数组保证是唯一的,所以会有一个总订单。有道理,我认为@rmaddy用他的
score
方法为我写了一个
myRelation
实现。我认为我的问题是我试图做一个匹配的解决方案,而排序和选择先让方式更敏感或挑剔:排序()如果您的属性真的被称为
prop1
prop2
等,Swift中的
方法将采用
。您可能应该