简体   繁体   English

一组对象中的属性如何符合 Swift 中的 Hashable 协议?

[英]How is possible to a property in a Set of objects conform to Hashable protocol in Swift?

I'm implementing a tag feature for an item list.我正在为项目列表实现标签功能。 I'm trying implementing a computed property that calculate the tag set in a list of item as the union of different tag set of each item like:我正在尝试实现一个计算属性,该属性将项目列表中的标签集计算为每个项目的不同标签集的并集,例如:

item1 - [tag1, tag2] item1 - [tag1, tag2]

item2 - [tag1, tag3] item2 - [tag1, tag3]

output > [tag1, tag2, tag3] output > [标签 1、标签 2、标签 3]

The problem is that the Tag class need to be hashable and an UID is given at each instance of the tag, even tag with the same description.问题是标签 class 需要是可哈希的,并且在标签的每个实例中都给出一个 UID,即使是具有相同描述的标签。 So when I loop in all the item taglist to create the tag set of the whole list the results is wrong like:因此,当我循环所有项目标签列表以创建整个列表的标签集时,结果是错误的,例如:

output > [tag1, tag1, tag2, tag3] output > [标签 1、标签 1、标签 2、标签 3]

Here's the code:这是代码:

class TTDItem: Identifiable {
    
    var id: UUID = UUID()
    var itemDesc: String
    var itemTags: Set<TTDTag>
    
    init(itemDesc: String, itemTags: Set<TTDTag>) {
        self.itemDesc = itemDesc
        self.itemTags = itemTags
    }
}

class TTDTag: Identifiable, Hashable {
    
    var TTDTagDesc: String
    var hashValue: Int {
        return id.hashValue
    }
    
    init(TTDTagDesc: String){
        self.TTDTagDesc = TTDTagDesc
    }
    
    static func ==(lhs: TTDTag, rhs: TTDTag) -> Bool {
        return lhs.id == rhs.id
    }
}

class TTDItemList {
    var itemList: [TTDItem]
    init(itemList: [TTDItem]) {
        self.itemList = itemList
    }
    //(...)
    // implement computed property taglist
    func itemTagsList()-> Set<TTDTag> {
        var tagSet = Set<TTDTag>()
        for item in self.itemList {
            tagSet = tagSet.union(item.itemTags)
        }
        return tagSet
    }
}

How can I access only to the tag description in order to obtain the correct result?我怎样才能只访问标签描述以获得正确的结果? Thanks谢谢

This can be done using reduce and the union function这可以使用reduceunion function 来完成

func itemTagsList()-> Set<TTDTag> {
    itemList.map(\.itemTags).reduce(Set<TTDTag>()){ $0.union($1) }
}

Note that for Hashable you need to implement hash(into:) for TTDTag请注意,对于Hashable您需要为TTDTag实现hash(into:)

func hash(into hasher: inout Hasher) {
    hasher.combine(TTDTagDesc)
} 

You should start property names with a lowercase letter and make them descriptive so maybe you could change TTDTagDesc to tagDescription您应该以小写字母开头的属性名称并使它们具有描述性,这样也许您可以将TTDTagDesc更改为tagDescription

hashValue is deprecated (and you should have received a warning for this). hashValue已弃用(您应该已经收到警告)。 You should override hash(into:) and use your TTDTagDesc property there.您应该覆盖hash(into:)并在那里使用您的TTDTagDesc属性。

Also, you should implement id to return TTDTagDesc , because that is what identifies a tag.此外,您应该实现id以返回TTDTagDesc ,因为这是标识标签的内容。

class TTDTag: Identifiable, Hashable {
    
    var TTDTagDesc: String

    // Note here
    func hash(into hasher: inout Hasher) {
        hasher.combine(TTDTagDesc)
    }
    
    // and here
    var id: String { TTDTagDesc }
    
    init(TTDTagDesc: String){
        self.TTDTagDesc = TTDTagDesc
    }
    
    static func ==(lhs: TTDTag, rhs: TTDTag) -> Bool {
        return lhs.id == rhs.id
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM