Last active
August 29, 2015 14:11
-
-
Save griotspeak/8bb4c46611fc90d3043b to your computer and use it in GitHub Desktop.
zipTailAndReduce
This file contains 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
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) | |
} |
This file contains 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
// 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