Insertion-Order Dictionary (like Java's LinkedHashMap) in Swift?

前端 未结 2 900
隐瞒了意图╮
隐瞒了意图╮ 2020-12-31 02:55

Is there a standard swift class that is a Dictionary, but keeps keys in insertion-order like Java\'s LinkedHashMap? If not, how would one be implemented?

2条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-31 03:15

    Swift 5 version:

    // OrderedDictionary behaves like a Dictionary except that it maintains
    //  the insertion order of the keys, so iteration order matches insertion
    //  order.
    struct OrderedDictionary {
        private var _dictionary: Dictionary
        private var _keys: Array
    
        init() {
            _dictionary = [:]
            _keys = []
        }
    
        init(minimumCapacity: Int) {
            _dictionary = Dictionary(minimumCapacity: minimumCapacity)
            _keys = Array()
        }
    
        init(_ dictionary: Dictionary) {
            _dictionary = dictionary
            _keys = dictionary.keys.map { $0 }
        }
    
        subscript(key: KeyType) -> ValueType? {
            get {
                _dictionary[key]
            }
            set {
                if newValue == nil {
                    self.removeValueForKey(key: key)
                } else {
                    _ = self.updateValue(value: newValue!, forKey: key)
                }
            }
        }
    
        mutating func updateValue(value: ValueType, forKey key: KeyType) -> ValueType? {
            let oldValue = _dictionary.updateValue(value, forKey: key)
            if oldValue == nil {
                _keys.append(key)
            }
            return oldValue
        }
    
        mutating func removeValueForKey(key: KeyType) {
            _keys = _keys.filter {
                $0 != key
            }
            _dictionary.removeValue(forKey: key)
        }
    
        mutating func removeAll(keepCapacity: Int) {
            _keys = []
            _dictionary = Dictionary(minimumCapacity: keepCapacity)
        }
    
        var count: Int {
            get {
                _dictionary.count
            }
        }
    
        // keys isn't lazy evaluated because it's just an array anyway
        var keys: [KeyType] {
            get {
                _keys
            }
        }
    
        var values: Array {
            get {
                _keys.map { _dictionary[$0]! }
            }
        }
    
        static func ==(lhs: OrderedDictionary, rhs: OrderedDictionary) -> Bool {
            lhs._keys == rhs._keys && lhs._dictionary == rhs._dictionary
        }
    
        static func !=(lhs: OrderedDictionary, rhs: OrderedDictionary) -> Bool {
            lhs._keys != rhs._keys || lhs._dictionary != rhs._dictionary
        }
    
    }
    
    extension OrderedDictionary: Sequence {
    
        public func makeIterator() -> OrderedDictionaryIterator {
            OrderedDictionaryIterator(sequence: _dictionary, keys: _keys, current: 0)
        }
    
    }
    
    struct OrderedDictionaryIterator: IteratorProtocol {
        let sequence: Dictionary
        let keys: Array
        var current = 0
    
        mutating func next() -> (KeyType, ValueType)? {
            defer { current += 1 }
            guard sequence.count > current else {
                return nil
            }
    
            let key = keys[current]
            guard let value = sequence[key] else {
                return nil
            }
            return (key, value)
        }
    
    }
    

    I didn't found way to make values 'lazy'.. need more research

提交回复
热议问题