Last active
August 24, 2016 15:39
-
-
Save flyinghyrax/f0b11db86687d034af99549fdb9f8f11 to your computer and use it in GitHub Desktop.
Implementing the cycle function for sequences in Swift
This file contains hidden or 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
/* 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