【问题标题】:Remove duplicate structs in array based on struct property in Swift根据 Swift 中的结构属性删除数组中的重复结构
【发布时间】:2016-11-04 08:29:05
【问题描述】:

我做了一个简单的结构体并实现了 Equatable 协议:

extension MyModelStruct: Equatable {}

func ==(lhs: NModelMatch, rhs: NModelMatch) -> Bool {
    let areEqual = lhs.id == rhs.id
    return areEqual
}

public struct MyModelStruct {

    var id : String?
    var staticId : String?

    init(fromDictionary dictionary: NSDictionary){
        id = dictionary["id"] as? String
        ...
}

然后在我的项目中,我得到一个 [MyModelStruct] 数组,我要做的是删除所有具有相同 id 的 MyModelStruct

let val1 = MyModelStruct(id:9, subId:1)
let val2 = MyModelStruct(id:10, subId:1)
let val3 = MyModelStruct(id:9, subId:10)

var arrayOfModel = [val1,val2,val3]; // or set but i do not know how to use a set
var arrayCleaned = cleanFunction[M2,M3] 

我怎样才能使 cleanFunction ?

有人可以帮忙吗。 谢谢大家。 Xcode:版本 7.3.1

【问题讨论】:

    标签: ios iphone swift ios9 ios10


    【解决方案1】:

    我真的不希望人们只接受答案,因为这是唯一的答案,这就是为什么我要向您展示如何使用集合的力量。集合用于任何没有意义的地方,无论它是否存在。集合提供了检查元素是否在集合中的快速方法 (contains)、删除元素 (remove)、组合两个集合 (union) 等等。人们通常只想要一个数组,因为他们熟悉它,但通常一个集合才是他们真正需要的。话虽如此,以下是使用集合的方法:

    struct Model : Hashable {
        var id : String?
    
        var hashValue: Int {
            return id?.hashValue ?? 0
        }
    }
    
    func ==(l: Model, r: Model) -> Bool {
        return l.id == r.id
    }
    
    let modelSet : Set = [
        Model(id: "a"),
        Model(id: "hello"),
        Model(id: "a"),
        Model(id: "test")
    ]
    
    // modelSet contains only the three unique Models
    

    要成为集合中的类型的唯一要求是Hashable 协议(它扩展了Equatable)。在您的情况下,您可以只返回String 的底层hashValue。如果您的 id 始终是一个数字(可能是),您应该将id 的类型更改为Int,因为Strings 的效率远低于Ints 并且它不会使感觉使用String。

    还可以考虑将此属性存储在某处,以便每次收到新模型时,您都可以这样做

    modelSet.unionInPlace(newModels)
    

    【讨论】:

      【解决方案2】:

      使用Set 而不是Array。

      【讨论】:

        【解决方案3】:

        如果你用这个函数扩展数组类型:

          extension Array
          {
             func uniqueValues<V:Equatable>( value:(Element)->V) -> [Element]
             {
                var result:[Element] = []
                for element in self
                {
                   if !result.contains({ value($0) == value(element) })
                   { result.append(element) }
                }
                return result
             }
          }
        

        您可以使用以下方法清除重复项:

          var arrayCleaned = arrayOfModel.uniqueValues({$0.id!})
        

        无需使结构 Equatable。

        请注意,如果您的数组非常大,这将不会很有效,并且您可能需要考虑在源头过滤插入到数组中的内容。

        【讨论】:

        • 我投了反对票,因为它的效率非常低,OP 不应该认为这是一个好主意
        【解决方案4】:

        我同意你最好使用 Set。您应该能够使用 Array 初始化 Set,例如 var arrayOfModel: Set = [val1, val2, val3]。但是因为您使用的是自定义类型,所以您需要确保 MyModelStruct 符合 hashable。 This link has a good explanation。

        但是如果你想使用数组那么你需要改变

        let areEqual = rhs.id == lhs.id
        

        到

        let areEqual = rhs.id == lhs.id && rhs.subId == lhs.subId)
        

        您需要修改您的结构以具有 subId 属性(并使变量 Int 而不是 String。

        在回答您的问题时,是的,您确实需要对数组进行迭代。

        【讨论】:

        • 我需要循环思考数组吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-12
        • 1970-01-01
        • 2021-06-30
        • 2017-08-22
        • 1970-01-01
        • 1970-01-01
        • 2021-04-12
        相关资源
        最近更新 更多