代码之家  ›  专栏  ›  技术社区  ›  taichino

在swift中,字典中是否可能有与多个键关联的相同集合实例?

  •  1
  • taichino  · 技术社区  · 8 年前

    我有一个 Set 实例并希望将其放入 Dictionary ,并将其与多个键关联,以便我将来可以查找/修改它。

    下面的Python代码是我想在Swift中实现的。

    s = set()
    D = {}
    D["a"] = s
    D["b"] = s
    
    D["a"].add("Hello")
    D["a"].add("World")
    print(D["b"]) # getting {"Hello", "World"} back
    

    我在斯威夫特尝试了一些类似跟踪的东西。

    var s = Set<String>()
    var D = Dictionary<String, Set<String>>()
    D["a"] = s // copy of s is assigned
    D["b"] = s // another copy of s is assigned
    
    D["a"]!.insert("Hello")
    D["a"]!.insert("World")
    print(D["b"]!) // empty :(
    

    由于Swift中的集合具有值语义,所以当我将集合放入字典时,就会创建新实例。有什么解决办法吗?我知道我可以 NSMutableSet 而不是斯威夫特的 设置 ,但我想知道如果可能的话,如何通过使用具有值语义的集合来实现这一点。

    1 回复  |  直到 8 年前
        1
  •  4
  •   Rob Napier    8 年前

    啊!现在我们进入了它的核心。您只需要基于stdlib的引用类型,而不是使用Foundation提供的引用类型。这很容易实现,虽然有点乏味。只需在类中包装一个集合。如果你不想吃饱 SetAlgebra Collection 一致性,您不必实现所有这些方法。(你可能还需要一些 init 方法使其更方便,但希望这些实现在您的代码需求中是显而易见的。)

    final class RefSet<Element> where Element: Hashable {
        private var storage: Set<Element> = Set()
        init() {}
    }
    
    extension RefSet: Equatable where Element: Equatable {
        static func == (lhs: RefSet<Element>, rhs: RefSet<Element>) -> Bool {
            return lhs.storage == rhs.storage
        }
    }
    
    extension RefSet: SetAlgebra {
        var isEmpty: Bool { return storage.isEmpty }
    
        func contains(_ member: Element) -> Bool {
            return storage.contains(member)
        }
    
        func union(_ other: RefSet<Element>) -> RefSet<Element> {
            return RefSet(storage.union(other.storage))
        }
    
        func intersection(_ other: RefSet<Element>) -> RefSet<Element> {
            return RefSet(storage.intersection(other.storage))
        }
    
        func symmetricDifference(_ other: RefSet<Element>) -> RefSet<Element> {
            return RefSet(storage.symmetricDifference(other.storage))
        }
    
        @discardableResult
        func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
            return storage.insert(newMember)
        }
    
        @discardableResult
        func remove(_ member: Element) -> Element? {
            return storage.remove(member)
        }
    
        @discardableResult
        func update(with newMember: Element) -> Element? {
            return storage.update(with: newMember)
        }
    
        func formUnion(_ other: RefSet<Element>) {
            storage.formUnion(other.storage)
        }
    
        func formIntersection(_ other: RefSet<Element>) {
            storage.formIntersection(other.storage)
        }
    
        func formSymmetricDifference(_ other: RefSet<Element>) {
            storage.formSymmetricDifference(other.storage)
        }
    }
    
    extension RefSet: Collection {
        typealias Index = Set<Element>.Index
        var startIndex: Index { return storage.startIndex }
        var endIndex: Index { return storage.endIndex }
    
        subscript(position: Index) -> Element {
            return storage[position]
        }
    
        func index(after i: Index) -> Index {
            return storage.index(after: i)
        }
    }