Let's look into how to implement Ordered Set.
Here is the example about how it works
let s = AppleOrderedSet<Int>()
s.add(1)
s.add(2)
s.add(-1)
s.add(0)
s.insert(4, at: 3)
print(s.all()) // [1, 2, -1, 4, 0]
s.set(-1, at: 0) // We already have -1 in index: 2, so we will do nothing here
print(s.all()) // [1, 2, -1, 4, 0]
s.remove(-1)
print(s.all()) // [1, 2, 4, 0]
print(s.object(at: 1)) // 2
print(s.object(at: 2)) // 4
The significant difference is the the array is not sorted. The elements in the array are the same when insert them. Image the array without duplicates and with O(logn)
or O(1)
search time.
The idea here is using a data structure to provide O(1)
or O(logn)
time complexity, so it's easy to think about hash table.
var indexOfKey: [T: Int]
var objects: [T]
indexOfKey
is used to track the index of the element. objects
is array holding elements.
We will go through some key functions details here.
Update indexOfKey
and insert element in the end of objects
// O(1)
public func add(_ object: T) {
guard indexOfKey[object] == nil else {
return
}
objects.append(object)
indexOfKey[object] = objects.count - 1
}
Insert in a random place of the array will cost O(n)
time.
// O(n)
public func insert(_ object: T, at index: Int) {
assert(index < objects.count, "Index should be smaller than object count")
assert(index >= 0, "Index should be bigger than 0")
guard indexOfKey[object] == nil else {
return
}
objects.insert(object, at: index)
indexOfKey[object] = index
for i in index+1..<objects.count {
indexOfKey[objects[i]] = i
}
}
If the object
already existed in the OrderedSet
, do nothing. Otherwise, we need to update the indexOfkey
and objects
.
// O(1)
public func set(_ object: T, at index: Int) {
assert(index < objects.count, "Index should be smaller than object count")
assert(index >= 0, "Index should be bigger than 0")
guard indexOfKey[object] == nil else {
return
}
indexOfKey.removeValue(forKey: objects[index])
indexOfKey[object] = index
objects[index] = object
}
Remove element in the array will cost O(n)
. At the same time, we need to update all elements's index after the removed element.
// O(n)
public func remove(_ object: T) {
guard let index = indexOfKey[object] else {
return
}
indexOfKey.removeValue(forKey: object)
objects.remove(at: index)
for i in index..<objects.count {
indexOfKey[objects[i]] = i
}
}
Written By Kai Chen