Skip to content

Instantly share code, notes, and snippets.

@Maksims
Last active December 20, 2015 21:09
Show Gist options
  • Save Maksims/6195423 to your computer and use it in GitHub Desktop.
Save Maksims/6195423 to your computer and use it in GitHub Desktop.
Collections that promise for single appearance of object in collection as well as use hashing based on key (if defined) for collection to speed up checks. In small collections that slows down (nearly unmeasurable) but in 'big' collections (32+) it is a great win to prevent iterations for searches.
'use strict';
var Collection = this.Collection = exports.Collection = function Collection(key) {
this.list = [ ];
this.length = 0;
this.key = key || null;
this.map = { };
}
// get if collection has item by function or item
Collection.prototype.has = function has(fnOrItem) {
if (typeof(fnOrItem) === 'function') { // function
for(var i = 0, len = this.list.length; i < len; ++i) {
if (fnOrItem(this.list[i])) {
return true;
}
}
} else { // item
if (this.key) {
return this.map[fnOrItem[this.key]] !== undefined;
} else {
for(var i = 0, len = this.list.length; i < len; ++i) {
if (this.list[i] === fnOrItem) {
return true;
}
}
}
}
return false;
};
// add item if not in list
Collection.prototype.push = function push(item) {
if (item instanceof Array) { // array
if (this.key) {
for(var i = 0, len = item.length; i < len; i++) {
if (this.map[item[i][this.key]] === undefined) {
this.list.push(item[i]);
this.map[item[i][this.key]] = item[i];
}
}
} else {
for(var n = 0, lenP = item.length; n < lenP; n++) {
for(var i = 0, len = this.list.length; i < len; i++) {
if (this.list[i] !== item) {
this.list.push(item[n]);
}
}
}
}
} else { // single
if (this.key) {
if (this.map[item[this.key]] !== undefined) {
return;
}
this.list.push(item);
this.map[item[this.key]] = item;
} else {
for(var i = 0, len = this.list.length; i < len; i++) {
if (this.list[i] === item) {
return;
}
}
this.list.push(item);
}
}
this.length = this.list.length;
};
// removes item from collection and returns it based on filter function or item
Collection.prototype.pull = function pull(fnOrKey) {
if (typeof(fnOrKey) === 'function') { // function
for(var i = 0, len = this.list.length; i < len; i++) {
item = this.list[i];
if (fnOrKey(item)) {
if (this.key) {
delete this.map[item[this.key]];
}
this.list.splice(i, 1);
this.length = this.list.length;
return item;
}
}
} else { // item
if (this.key && this.map[fnOrKey] !== undefined) {
var item = this.map[fnOrKey];
for(var i = 0, len = this.list.length; i < len; i++) {
if (this.list[i] === item) {
this.list.splice(i, 1);
this.length = this.list.length;
delete this.map[fnOrKey];
return item;
}
}
}
}
return null;
};
// remove by item or filter function
Collection.prototype.remove = function remove(fnOrItem) {
if (typeof fnOrItem === 'function') { // by function
for(var i = 0, len = this.list.length; i < len; i++) {
if(fnOrItem(this.list[i])) {
if (this.key) {
delete this.map[this.list[i][this.key]];
}
this.list.splice(i, 1);
this.length = this.list.length;
return true;
}
}
} else { // by object
for(var i = 0, len = this.list.length; i < len; i++) {
if ((this.key && this.list[i][this.key] == fnOrItem[this.key]) || (this.list[i] === fnOrItem)) {
if (this.key) {
delete this.map[this.list[i][this.key]];
}
this.list.splice(i, 1);
this.length = this.list.length;
return true;
}
}
}
return false;
};
// get array (optionally filtered by function)
Collection.prototype.toArray = function toArray(fn) {
var res = [ ];
if (fn) {
for(var i = 0, len = this.list.length; i < len; ++i) {
if (fn(this.list[i])) {
res.push(this.list[i]);
}
}
} else {
for(var i = 0, len = this.list.length; i < len; ++i) {
res.push(this.list[i]);
}
}
return res;
};
// clear
Collection.prototype.clear = function clear() {
this.list = [ ];
this.map = { };
this.length = 0;
};
// returns item by filter function or key
Collection.prototype.get = function get(fnOrKey) {
if (typeof(fnOrKey) === 'function') { // function
for(var i = 0, len = this.list.length; i < len; i++) {
if (fnOrKey(this.list[i])) {
return this.list[i];
}
}
} else { // key
if (this.key && this.map[key] !== undefined) {
return this.map[key];
}
}
return null;
};
// return filtered list
Collection.prototype.filter = function filter(fn) {
return this.list.filter(fn);
};
// for each call function
Collection.prototype.forEach = function forEach(fn) {
for(var i = 0, len = this.list.length; i < len; ++i) {
fn(this.list[i]);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment