Skip to content

Instantly share code, notes, and snippets.

@griotspeak
Last active August 29, 2015 14:11
Show Gist options
  • Save griotspeak/8bb4c46611fc90d3043b to your computer and use it in GitHub Desktop.
Save griotspeak/8bb4c46611fc90d3043b to your computer and use it in GitHub Desktop.
zipTailAndReduce
extension Slice {
func zipWithTail() -> Zip2<Slice<T>, Slice<T>> {
return Zip2(self, dropFirst(self))
}
}
extension Array {
func zipWithTail() -> Zip2<[T], Slice<T>> {
return Zip2(self, dropFirst(self))
}
/// Array must contain more than 1 element
func zipTailAndReduce<U>(seedBlock:(T, T) -> U, combine:(U, (T, T)) -> U) -> U {
precondition(self.count > 1, "Array.zipTailAndReduce: count must be greater than 1")
let firstIndex = self.startIndex
let firstElement = self[firstIndex]
let secondIndex = firstIndex.successor()
let secondElement = self[secondIndex]
let seed = seedBlock(firstElement, secondElement)
switch self.count {
case 0, 1:
preconditionFailure("Array.zipTailAndReduce: somehow evaded first length check. Madness.")
case 2:
return seed
case 3:
return combine(seed, (secondElement, self[secondIndex.successor()]))
default:
let thirdIndex = secondIndex.successor()
let theRest = self[thirdIndex..<self.endIndex].zipWithTail()
return Swift.reduce(theRest, seedBlock(firstElement, secondElement), combine)
}
}
}
private func _zipTailAndReduceLoop<G : GeneratorType, T, U where T == G.Element>(inout generator:G, combine:(U, (T, T)) -> U, #accum:U, #ultimate:T) -> U {
if let item = generator.next() {
return _zipTailAndReduceLoop(&generator, combine, accum: combine(accum, (ultimate, item)), ultimate: item)
} else {
return accum
}
}
public func zipTailAndReduce<S : SequenceType, T, U where T == S.Generator.Element>(seq:S, seedBlock:(T, T) -> U, combine:(U, (T, T)) -> U) -> U {
func unwrap(optionalX:T?) -> T {
if let x = optionalX {
return x
} else {
preconditionFailure("SequenceType.zipTailAndReduce: element count must be greater than 1")
}
}
var theGenerator = seq.generate()
let firstElement:T = unwrap(theGenerator.next())
let secondElement:T = unwrap(theGenerator.next())
let seed:U = seedBlock(firstElement, secondElement)
return _zipTailAndReduceLoop(&theGenerator, combine, accum: seed, ultimate: secondElement)
}
// which is all to enable code like this
public func isSorted<T:Comparable>(list:[T], comparator:(T, T) -> Bool) -> Bool {
switch list.count {
case 0, 1:
return true
default:
return list.zipTailAndReduce(comparator) { (listIsSorted, pair) -> Bool in
(listIsSorted) ? comparator(pair.0, pair.1) : false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment