Created
May 3, 2020 12:07
-
-
Save Hiroki-Kawakami/5903b7d8aa225fc9318181ca3a5d1637 to your computer and use it in GitHub Desktop.
Ordered Dictionary in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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