As per the Swift Documentation when conforming to the Collection
protocol:
Types that conform to Collection are expected to provide the startIndex and endIndex properties and subscript access to elements as O(1) operations.
How can subscript be returned in constant time? Wouldn't it need to iterate through the collection, up to the correct index, and then return that value?
This is the LinkedList that I'm using to conform to Collection
:
indirect enum LinkedList<T> {
case value(element: T, next: LinkedList<T>)
case end
}
extension LinkedList: Sequence {
func makeIterator() -> LinkedListIterator<T> {
return LinkedListIterator(current: self)
}
var underestimatedCount: Int {
var count = 0
for _ in self {
count += 1
}
return count
}
}
struct LinkedListIterator<T>: IteratorProtocol {
var current: LinkedList<T>
mutating func next() -> T? {
switch current {
case let .value(element, next):
current = next
return element
case .end:
return nil
}
}
}
And here is this is where I actually conform to the protocol:
extension LinkedList: Collection {
typealias Index = Int
typealias Element = T
var startIndex: Index {
return 0
}
var endIndex: Index {
return underestimatedCount
}
func index(after i: Index) -> Index {
return (i < endIndex) ? i + 1 : endIndex
}
subscript (position: Index) -> Element {
precondition(position < endIndex && position >= startIndex)
var iterator = makeIterator()
for i in 0 ..< position {
iterator.next()
if i + 1 == position {
return iterator.next()!
}
}
var zero = makeIterator()
return zero.next()!
}
}
let test = LinkedList<Int>.value(element: 2, next: LinkedList<Int>.value(element: 4, next: LinkedList<Int>.value(element: 7, next: LinkedList<Int>.value(element: 9, next: LinkedList<Int>.end))))
The collection's
Index
does not have to be anInt
. One possible approach is to use a custom index type which has a reference to the corresponding element. However this requires the list nodes to be instances of a class.Here is something that I came up with. It can probably be improved, but hopefully demonstrates the idea.
class ListNode
stores the element and a pointer to the next node, and in addition, an increasing integerordinal
, which is used to makestruct ListIndex
adopt theComparable
protocol.struct ListIndex
contains a reference to the list node, ornil
forendIndex
.Example usage: