Skip to content

Instantly share code, notes, and snippets.

@Hiroki-Kawakami
Created May 3, 2020 12:07
Show Gist options
  • Save Hiroki-Kawakami/5903b7d8aa225fc9318181ca3a5d1637 to your computer and use it in GitHub Desktop.
Save Hiroki-Kawakami/5903b7d8aa225fc9318181ca3a5d1637 to your computer and use it in GitHub Desktop.
Ordered Dictionary in Swift
import Foundation
struct OrderedDictionary<Key: Hashable, Value>: Sequence, IteratorProtocol, CustomStringConvertible {
private(set) var keys = [Key]()
private var dictionary = [Key: Value]()
init() {}
init(dictionary: [Key: Value], order: [Key]) {
self.keys = order
self.dictionary = dictionary
}
init(keys: [Key], values: [Value]) {
self.keys = keys
for i in 0..<Swift.min(keys.count, values.count) {
self.dictionary[keys[i]] = values[i]
}
}
subscript(index: Int) -> Value {
return dictionary[keys[index]]!
}
subscript(key: Key) -> Value? {
return dictionary[key]
}
var count: Int {
return keys.count
}
var values: [Value] {
return keys.compactMap({ dictionary[$0] })
}
var first: (key: Key, value: Value)? {
if count > 0 { return (keys[0], self[0]) }
return nil
}
var last: (key: Key, value: Value)? {
if count > 0 { return (keys[count - 1], self[count - 1]) }
return nil
}
var description: String {
let str = keys.reduce("", { "\($0), \($1): \(dictionary[$1]!)"})
return "[" + str[str.index(str.startIndex, offsetBy: 2)...] + "]"
}
mutating func append(_ value: Value, for key: Key) {
keys.append(key)
dictionary[key] = value
}
mutating func insert(_ value: Value, for key: Key, at index: Int) {
keys.insert(key, at: index)
dictionary[key] = value
}
@discardableResult
mutating func remove(at index: Int) -> (key: Key, value: Value) {
let key = keys.remove(at: index)
defer {
dictionary[key] = nil
}
return (key, dictionary[key]!)
}
@discardableResult
mutating func remove(for key: Key) -> Value? {
if let index = keys.firstIndex(of: key) {
return remove(at: index).value
}
return nil
}
func firstIndex(where predicate: ((key: Key, value: Value)) throws -> Bool) rethrows -> Int {
for (i, key) in keys.enumerated() {
if try predicate((key, dictionary[key]!)) { return i }
}
return -1
}
// Iterator
var iteratorCount = 0
mutating func makeIterator() -> OrderedDictionary<Key, Value> {
iteratorCount = 0
return self
}
mutating func next() -> (key: Key, value: Value)? {
defer { iteratorCount += 1 }
return iteratorCount < count ? (keys[iteratorCount], self[iteratorCount]) : nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment