【问题标题】:How do I create a Set of custom objects (Swift)?如何创建一组自定义对象 (Swift)?
【发布时间】:2015-12-02 06:07:06
【问题描述】:

对于我的 iOS 应用,我有一个类似的模型

class Person {
    var Id: Int
    var Name: String

    init(id: Int, name: String?) {
        self.Id = id
        self.Name = name ?? ""
    }
}

然后在我的ViewController 中,当我从服务器加载数据时,我将一些人添加到数组中

class ViewController: UIViewController {
    var people:[Person] = []

    override func viewDidLoad() {
        self.loadPeople()
    }

    func loadPeople() {
        // This data will be coming from a server request
        // so is just sample. It could have users which 
        // already exist in the people array

        self.people.append(Person(id: "1", name: "Josh"))
        self.people.append(Person(id: "2", name: "Ben"))
        self.people.append(Person(id: "3", name: "Adam"))
    }
}

我现在要做的是将people 数组转换为Set<Person>,这样它就不会添加重复项。这是可能的还是我需要改变我的逻辑?

【问题讨论】:

    标签: ios swift set equatable


    【解决方案1】:

    更新

    使用 hashValue 时的弃用警告:

    'Hashable.hashValue' 作为协议要求已被弃用;符合 通过实现 'hash(into:)' 将 'Person' 类型改为 'Hashable'

    按照对象 Person 示例,现在的实现将是:

    class Person: Equatable, Hashable {
    
        let id: Int
        let countryId: Int
        var name: String
        
        init(id: Int, countryId: Int, name: String) {
            self.id = id
            self.countryId = countryId
            self.name = name
        }
        
        func hash(into hasher: inout Hasher) {
            hasher.combine(id)
            hasher.combine(countryId)
        }
        
        static func == (lhs: Person, rhs: Person) -> Bool {
            return lhs.id == rhs.id &&  lhs.countryId == rhs.countryId
        }
        
    }
    

    注意:根据文档,用于散列的组件必须与您类型的 == 运算符实现中比较的组件相同。

    【讨论】:

      【解决方案2】:

      在 Swift 2.0 中,Hashable 和 Equitable 是 NSObject 的一部分。您需要做的就是为感兴趣的属性覆盖“isEqual”和“var hash:”。在这种情况下:“Id”,Set 将排除具有相同 Id 的 Person-objects。

          class Person: NSObject {
              var Id: Int
              var Name: String
      
              init(id: Int, name: String?) {
                  self.Id = id
                  self.Name = name ?? ""
              }
      
              override var hash: Int {
              return Id.hashValue
         }
      
              override func isEqual(object: AnyObject?) -> Bool {
                  guard let rhs = object as? Person else {
                      return false
                  }
                  let lhs = self
      
                  return lhs.Id == rhs.Id
              }
      
      
          }
      
                func mergeArrays(){
             let person1 = Person(id: 1, name: "Tom")
             let person2 = Person (id: 2, name: "John")
             let person3 = Person(id: 3, name: "Adam")
      
      
             let downloadedPeople  = [person1,person2] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 2, Name "John"}] 
      
             let peopleStoredLocally = [person1,person3] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 3, Name "Adam"}]
      
             let downloadedPeopleSet = Set(downloadedPeople) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 1, Name "Tom"}}
      
      
             let mergedSet = downloadedPeopleSet.union(peopleStoredLocally) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}}
      
      
             let mergedArray = Array(mergedSet)//[{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}]
      
          }
      

      【讨论】:

      • 你可能不应该在 swift 应用程序中使用 objC 类型,除非你真的必须这样做。所以我建议使用独立协议而不是从 NSObject 继承。
      【解决方案3】:

      要设置Person,您需要使其符合 Equatable 和 Hashable 协议:

      class Person: Equatable, Hashable {
          var Id: Int
          var Name: String
      
          init(id: Int, name: String?) {
              self.Id = id
              self.Name = name ?? ""
          }
      
          var hashValue: Int {
              get {
                  return Id.hashValue << 15 + Name.hashValue
              }
          }
      }
      
      func ==(lhs: Person, rhs: Person) -> Bool {
          return lhs.Id == rhs.Id && lhs.Name == rhs.Name
      }
      

      那么你可以像这样使用一组人:

      var set = Set<Person>()
      set.insert(Person(id: 1, name: "name"))
      

      【讨论】:

      • 我个人使用 XOR 来组合哈希,但 +1 用于在您的答案中包含 Hashable 协议。
      • Hashable 继承自 Equatable,因此将类声明为 class Person: Hashable { ... } 就足够了。当然,显式添加 Equatable 并没有什么坏处。
      • @egor.zhdan 你能解释一下移位位 15 的部分,为什么你在那里使用 15 吗?
      • @lennard 我正在使用位移,因为它(可能)减少了哈希冲突。使用 15 没有充分的理由 - 您可以使用 Id.hashValue &lt;&lt; 30 + Name.hashValue,它会起作用。
      猜你喜欢
      • 1970-01-01
      • 2018-05-14
      • 1970-01-01
      • 2015-05-15
      • 2014-06-20
      • 2018-01-09
      • 1970-01-01
      • 2021-07-26
      • 1970-01-01
      相关资源
      最近更新 更多