Skip to content

Instantly share code, notes, and snippets.

@jremmen
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jremmen/de4a11c5e86eb9374d83 to your computer and use it in GitHub Desktop.
Save jremmen/de4a11c5e86eb9374d83 to your computer and use it in GitHub Desktop.
lazy iterator
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