Swift 3 Equatable Struct可选功能

时间:2017-03-10 14:52:19

标签: swift

这将是一个有点长的啰嗦,所以请耐心等待。我也是一个快速的初学者。我有一个定义了struct的数组。

var modelOriginalArray                      = [model]()

struct model: Equatable  {
    var modelID         = String()
    var modelName       = String()
    var modelNumber     = String()
    var manufacturer    = String()
    var manufShort      = String()
    var phiTypeCode     = String()
    var phiTypeDesc     = String()


    init(modelID: String, modelName: String, modelNumber: String, manufacturer: String, manufShort: String, phiTypeCode: String, phiTypeDesc: String) {
        self.modelID        = modelID
        self.modelName      = modelName
        self.modelNumber    = modelNumber
        self.manufacturer   = manufacturer
        self.manufShort     = manufShort
        self.phiTypeCode    = phiTypeCode
        self.phiTypeDesc    = phiTypeDesc
    }

    static func == (lhs: model, rhs: model) -> Bool {
        return lhs.manufShort == rhs.manufShort && lhs.modelName == rhs.modelName && lhs.modelNumber == rhs.modelNumber
    }


}

我将大约5000条记录加载到此数组中。然后我需要根据搜索条件过滤此数组。让我们说我正在寻找制造商"索尼"。索尼可能有多种型号,所以我需要将所有索尼记录与5000以上的记录分开。

    srchval = "SONY"
    var filteredArray = [model]()
    var uniqueFilteredArray = [model]()

    filteredArray = self.modelOriginalArray.filter { $0.manufShort.range(of: srchval, options: .caseInsensitive) != nil }

这将给我一个只有"索尼"记录。然而,其中一些"索尼"记录在不同的 modelID 下有重复的 manufShort modelName modelNumber 值。我需要将它们分开并且只有独特的记录。

    // Find Uniquic options by removing duplicate Model Names
    uniqueFilteredArray = unique(models: filteredArray)


func unique(models: [model]) -> [model] {

    var uniqueModels = [model]()

    for model in models {
        if !uniqueModels.contains(model) {
            uniqueModels.append(model)
        }
    }

    return uniqueModels
}

这一切都很有效。我遇到的问题是在过滤器中有必须确保记录匹配的情况:

    static func == (lhs: model, rhs: model) -> Bool {
        return lhs.manufShort == rhs.manufShort && lhs.modelName == rhs.modelName && lhs.modelNumber == rhs.modelNumber
    }

在同一课程的不同情况下,我只需要匹配 manufShort

    static func == (lhs: model2, rhs: model2) -> Bool {
        return lhs.manufShort == rhs.manufShort
    }

我尝试使用这个不同的静态函数创建一个单独的模型,即model2,但是我很难将数据从一个数组移动到另一个数组,并且具有不同的结构。

有任何想法或更好的方法来实现这一目标吗?

由于

2 个答案:

答案 0 :(得分:0)

您可以在Collection上使用以下扩展程序。未经测试。

extension Collection where Iterator.Element: Equatable {
    func uniques(by equals: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] {
        var uniqueElems: [Iterator.Element] = []
        for elem in self {
            if uniqueElems.index(where: { equals($0, elem) }) == nil {
                uniqueElems.append(elem)
            }
        }
        return uniqueElems
    }   
}

然后你可以使用

filteredArray.uniques { $0.manufShort == $1.manufShort }
filteredArray.uniques { $0.manufShort == $1.manufShort && $0.modelName == $1.modelName && $0.modelNumber == $1.modelNumber }

答案 1 :(得分:0)

由于您使用两种不同的方法来定义"相等"在两个模型中,您可能应该考虑不使用==运算符,因为如果等式谓词因具体情况而异,则您不会真正测试相等性。相反,您有两个不同的自定义谓词(适用于两个模型实例),您希望在不同的上下文中使用它们。为什么不使用两个自定义类型(静态)方法,使用描述性名称,从语义上描述它们的不同含义?

  

谢谢!这很有意义,我如何调用不同的(静态)方法,以便根据我所追求的内容找到正确的函数。一个例子?

示例设置:

struct Foo {
    let id: String
    let bar: Int
    let baz: Int
    let bax: Int
    init(_ id: String, _ bar: Int, _ baz: Int, _ bax: Int)
    {
        self.id = id
        self.bar = bar
        self.baz = baz
        self.bax = bax
    }

    static func byBarEqualityPredicate(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.bar == rhs.bar 
    }

    static func byBazAndBaxEqualityPredicate(lhs: Foo, rhs: Foo) -> Bool {
        return lhs.baz == rhs.baz && lhs.bax == rhs.bax 
    }
}

let fooArr = [Foo("Foo A", 1, 2, 3),
              Foo("Foo B", 1, 1, 2),
              Foo("Foo C", 3, 1, 2)]

unique方法的略微修改版本,现在在(Foo, Foo) -> Bool数组中提供foos谓词:

func unique(foos: [Foo], predicate: (Foo, Foo) -> Bool) -> [Foo] {
    var uniqueFoos = [Foo]()
    for foo in foos {
        if !uniqueFoos.contains(where: { predicate($0, foo) }) {
            uniqueFoos.append(foo)
        }
    }
    return uniqueFoos
}

使用两个不同的Foo谓词进行测试:

// by 'bar' "equality": Foo A and Foo B will be considered "equal",
// and only Foo A, among these two , will be added to the "unique" array.
let fooWithBarPredicate = unique(foos: fooArr, predicate: Foo.byBarEqualityPredicate)
fooWithBarPredicate.forEach { print($0.id) } // Foo A, Foo C

// by 'baz' && 'bax' "equality": Foo A and Foo C will be considered "equal",
// and only Foo A, among these two, will be added to the "unique" array.
let fooWithBazBaxPredicate = unique(foos: fooArr, predicate: Foo.byBazAndBaxEqualityPredicate)
fooWithBazBaxPredicate.forEach { print($0.id) } // Foo A, Foo B