Skip to content

Instantly share code, notes, and snippets.

@flyinghyrax
Last active August 24, 2016 15:39
Show Gist options
  • Save flyinghyrax/f0b11db86687d034af99549fdb9f8f11 to your computer and use it in GitHub Desktop.
Save flyinghyrax/f0b11db86687d034af99549fdb9f8f11 to your computer and use it in GitHub Desktop.
Implementing the cycle function for sequences in Swift
/* Copied from a playground file */
// Produce a list of length N by cycling an original list
func cycleN<T>(base: [T], length: Int) -> [T] {
var buildup: [T] = []
while buildup.count < length {
buildup.appendContentsOf(base)
}
return Array(buildup.prefix(length))
}
// same as a sequence extension
extension SequenceType {
func cycle(count n: Int) -> AnySequence<Generator.Element> {
var result: [Generator.Element] = []
while result.count < n {
result.appendContentsOf(self)
}
return AnySequence(result.prefix(n))
}
}
let it = Array([1,2,3].cycle(count: 4))
// some helpers for the lazy version
extension Array {
// Single element circular left shift
mutating func rotate() {
if let oldFirst = self.popFirst() {
self.append(oldFirst)
}
}
mutating func popFirst() -> Element? {
if self.first != nil {
return self.removeFirst()
} else {
return nil
}
}
// Single element circular left shift
func rotated() -> Array<Element> {
if let first = self.first {
var t = Array(self.dropFirst())
t.append(first)
return t
} else {
return self
}
}
}
var some = [1,2,3]
some.rotate()
some.rotate()
some.rotate()
let other = [1,2,3,4]
other.rotated().rotated()
Array<Int>().rotated()
// Infinitae lazy cycles
struct LazyCycleGenerator<Base: GeneratorType>: GeneratorType {
mutating func next() -> Base.Element? {
// while the base hasn't run out yet, just return elements from that
if let next = base.next() {
used.append(next)
return next
} else if let next = used.first {
used.rotate()
return next
}
return nil
}
init(base: Base) {
self.base = base
}
// This may itself be lazy, and may be consumed by iteration.
// If it's consumable, how do we repeat it?
private var base: Base
// I guess we have to keep a copy, which isn't efficient but shrug...
private var used: [Base.Element] = []
}
struct LazyCycleSequence<Base: SequenceType>: LazySequenceType {
func generate() -> LazyCycleGenerator<Base.Generator> {
return LazyCycleGenerator(base: base.generate())
}
private let base: Base
}
extension LazySequenceType {
func cycle() -> LazyCycleSequence<Self> {
return LazyCycleSequence(base: self)
}
}
Array([1,2,3].lazy.cycle().prefix(5))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment