Skip to content

Instantly share code, notes, and snippets.

@bkase
Last active March 12, 2017 08:33
Show Gist options
  • Save bkase/3f5873d140b9eb35afd56d579a0952bf to your computer and use it in GitHub Desktop.
Save bkase/3f5873d140b9eb35afd56d579a0952bf to your computer and use it in GitHub Desktop.
LazyCollection behavior when indexing directly via subscript

I received a great question over email that I want to answer publicly via gist:

At the end [of the Grokking Lazy Sequences and Collections talk], someone asked you if they can just access a lazy collection randomly and it will not run the transform (map for example) on every element in the collection up to the one they chose.

You said that is correct, but I think that it only applies if the Collection is a RandomAccessCollection? Otherwise, access is not random and is sequential instead, so the iterator’s next() method will be called on each element up to the one requested, and that transform will be executed on each one.

Actually, my response is correct! Confusingly, Collection does support subscript random access (with an expected O(1) runtime in fact) if you have an index. RandomAccessCollection conformance implies that you can compute the distance between indicies in O(1) time (aka moving an index is fast).

If you do happen to have an index for a lazy collection (even a non-RandomAccessCollection) you can index into it without calling next() over and over again (this is in contrast to Sequence where that would be expected), so you only need to invoke one transform on a LazyCollection.

Proof: http://swift.sandbox.bluemix.net/#/repl/58c4f4c1579d675918b224f5

Attached:

import Foundation

struct SomeCollection<T>: Collection {
    private let xs: Array<T>

    init(_ xs: Array<T>) {
        self.xs = xs
    }

    var startIndex: Int {
        return 0
    }

    var endIndex: Int {
        return xs.count
    }

    func index(after i: Int) -> Int {
        return i + 1
    }

    subscript(i: Int) -> T {
        return xs[i]
    }
}

let c: SomeCollection<Int> = SomeCollection([1, 2, 3, 4, 5, 6])
print(c.lazy.map{ x in print("hello"); return x + 1 }[4])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment