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

时间:2018-04-26 20:16:45

标签: swift collections

我有一个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

我在Swift中尝试了类似的内容。

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而不是Swift的Set,但我想知道如果可能的话,我可以通过使用带有值语义的集合来解决这个问题。

1 个答案:

答案 0 :(得分:4)

啊!现在我们了解它的核心。您只需要一个基于stdlib的引用类型,而不是使用Foundation提供的引用类型。如果稍微单调乏味,那就很容易实现。只需在一个类中包装一个Set。如果您不想完全SetAlgebraCollection一致,则不必实施所有这些方法。 (并且您可能需要更多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)
    }
}