Last active
August 29, 2015 14:19
-
-
Save jremmen/de4a11c5e86eb9374d83 to your computer and use it in GitHub Desktop.
lazy iterator
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
var Iterator = function(m, n) { | |
this.start = m; | |
this.end = n || Infinity; | |
this.step = 1; | |
this.current = this.start; | |
this.queue = new IteratorQueue(); | |
this.next = function() { | |
var c = this.current; | |
this.current += this.step; | |
return this._next_iter(this.queue, c); | |
} | |
this.filters = function(q, n) { | |
for (var i = 0; i < q.filters.length; i++) { | |
if (!q.filters[i].call(n)) return false; | |
} | |
return true; | |
}; | |
this.maps = function(q, n) { | |
var v = n; | |
q.maps.forEach(function(f) { | |
v = f.call(v); | |
}); | |
return v; | |
}; | |
this.step_by = function(n) { | |
this.step = n; | |
return this; | |
} | |
this.each = function(f) { | |
while ((n = this.next()) || n !== null) { f(n); } | |
}; | |
this.map = function(f) { | |
this._enqueue(new IteratorMap(f)); | |
return this; | |
}; | |
this.filter = function(f) { | |
this._enqueue(new IteratorFilter(f)); | |
return this; | |
}; | |
this.reduce = function(a, f) { | |
acc = a; | |
while ((n = this.next()) || n !== null) { | |
acc = f(acc, n); | |
} | |
return acc; | |
}; | |
this.take = function(n) { | |
arr = []; | |
while (n-- > 0 && ((v = this.next()) || v !== null)) arr.push(v); | |
return arr; | |
}; | |
this.collect = function() { | |
var arr = []; | |
while ((n = this.next()) || n !== null) arr.push(n); | |
return arr; | |
} | |
this._enqueue = function(f) { | |
return this.queue.enqueue(f); | |
}; | |
this._next_iter = function(q, v) { | |
// exhausted the iterator before finding a value | |
if (this.current-1 > this.end) return null; | |
// blew thru all of the queue without exhausting the iterator | |
// so this must be the value we want | |
if (!q.length) return v; | |
// apply head queue map functions to get a value | |
var w = this.maps(q[0], v); | |
// our value didnt pass the head queue filters | |
// so start over from the beginning using the next base value | |
if (!this.filters(q[0], w)) { | |
return this.next(); | |
// our value passed the current queue filters | |
// so recurse with the value and the tail of queues | |
} else { | |
return this._next_iter(q.slice(1), w); | |
} | |
}; | |
} | |
var IteratorFilter = function(f) { | |
this.call = f; | |
} | |
var IteratorMap = function(f) { | |
this.call = f; | |
} | |
var IteratorQueueSequence = function() { | |
this.filters = []; | |
this.maps = []; | |
} | |
var IteratorQueue = function() { | |
this.enqueue = function(f) { | |
var q = this[this.length-1]; | |
if (f instanceof IteratorFilter) q.filters.push(f); | |
else if (!q.filters.length) q.maps.push(f); | |
else { | |
q = new IteratorQueueSequence(); | |
q.maps.push(f); | |
this.push(q); | |
} | |
return this; | |
} | |
this.push(new IteratorQueueSequence()); | |
} | |
IteratorQueue.prototype = (function() { | |
var F = function() {}; | |
F.prototype = Array.prototype; | |
return new F(); | |
})(); | |
Array.prototype.iter = function() { | |
return new Iterator(this[0], this[this.length-1]); | |
} | |
function iter(m, n) { return new Iterator(m, n); } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment