Comparing version 0.2.5 to 0.2.7
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
module.exports = require('./src/HashArray.js'); | ||
},{"./src/HashArray.js":3}],2:[function(require,module,exports){ | ||
/*! | ||
@@ -212,7 +210,16 @@ * jclass v1.0.1 | ||
},{}],3:[function(require,module,exports){ | ||
},{}],2:[function(require,module,exports){ | ||
/*===========================================================================*\ | ||
* Requires | ||
\*===========================================================================*/ | ||
var JClass = require('jclass'); | ||
/*===========================================================================*\ | ||
* HashArray | ||
\*===========================================================================*/ | ||
var HashArray = JClass._extend({ | ||
init: function(keyFields, callback) { | ||
//----------------------------------- | ||
// Constructor | ||
//----------------------------------- | ||
init: function(keyFields, callback, options) { | ||
keyFields = keyFields instanceof Array ? keyFields : [keyFields]; | ||
@@ -228,2 +235,6 @@ | ||
this.options = options || { | ||
ignoreDuplicates: false | ||
}; | ||
if (callback) { | ||
@@ -233,24 +244,33 @@ callback('construct'); | ||
}, | ||
add: function() { | ||
for (var i = 0; i < arguments.length; i++) { | ||
var obj = arguments[i], | ||
needsDupCheck = false; | ||
for (var key in this.keyFields) { | ||
key = this.keyFields[key]; | ||
var inst = this.find(obj, key); | ||
if (inst) { | ||
if (this._map[inst]) { | ||
if (this._map[inst].indexOf(obj) != -1) { | ||
// Cannot add the same item twice | ||
needsDupCheck = true; | ||
continue; | ||
} | ||
this._map[inst].push(obj); | ||
} else this._map[inst] = [obj]; | ||
//----------------------------------- | ||
// add() | ||
//----------------------------------- | ||
addOne: function (obj) { | ||
var needsDupCheck = false; | ||
for (var key in this.keyFields) { | ||
key = this.keyFields[key]; | ||
var inst = this.objectAt(obj, key); | ||
if (inst) { | ||
if (this._map[inst]) { | ||
if (this.options.ignoreDuplicates) | ||
return; | ||
if (this._map[inst].indexOf(obj) != -1) { | ||
// Cannot add the same item twice | ||
needsDupCheck = true; | ||
continue; | ||
} | ||
this._map[inst].push(obj); | ||
} | ||
else this._map[inst] = [obj]; | ||
} | ||
} | ||
if (!needsDupCheck || this._list.indexOf(obj) == -1) | ||
this._list.push(obj); | ||
if (!needsDupCheck || this._list.indexOf(obj) == -1) | ||
this._list.push(obj); | ||
}, | ||
add: function() { | ||
for (var i = 0; i < arguments.length; i++) { | ||
this.addOne(arguments[i]); | ||
} | ||
if (this.callback) { | ||
@@ -283,2 +303,45 @@ this.callback('add', Array.prototype.slice.call(arguments, 0)); | ||
}, | ||
//----------------------------------- | ||
// Intersection, union, etc. | ||
//----------------------------------- | ||
/** | ||
* Returns a new HashArray that contains the intersection between this (A) and the hasharray passed in (B). Returns A ^ B. | ||
*/ | ||
intersection: function (other) { | ||
var self = this; | ||
if (!other || !other.isHashArray) | ||
throw Error('Cannot HashArray.intersection() on a non-hasharray object. You passed in: ', other); | ||
var ret = this.clone(null, true), | ||
allItems = this.clone(null, true).addAll(this.all.concat(other.all)); | ||
allItems.all.forEach(function (item) { | ||
if (self.collides(item) && other.collides(item)) | ||
ret.add(item); | ||
}); | ||
return ret; | ||
}, | ||
/** | ||
* Returns a new HashArray that contains the complement (difference) between this hash array (A) and the hasharray passed in (B). Returns A - B. | ||
*/ | ||
complement: function (other) { | ||
var self = this; | ||
if (!other || !other.isHashArray) | ||
throw Error('Cannot HashArray.complement() on a non-hasharray object. You passed in: ', other); | ||
var ret = this.clone(null, true); | ||
this.all.forEach(function (item) { | ||
if (!other.collides(item)) | ||
ret.add(item); | ||
}); | ||
return ret; | ||
}, | ||
//----------------------------------- | ||
// Retrieval | ||
//----------------------------------- | ||
get: function(key) { | ||
@@ -333,8 +396,21 @@ return (!(this._map[key] instanceof Array) || this._map[key].length != 1) ? this._map[key] : this._map[key][0]; | ||
}, | ||
//----------------------------------- | ||
// Peeking | ||
//----------------------------------- | ||
has: function(key) { | ||
return this._map.hasOwnProperty(key); | ||
}, | ||
collides: function (item) { | ||
for (var k in this.keyFields) | ||
if (this.has(this.objectAt(item, this.keyFields[k]))) | ||
return true; | ||
return false; | ||
}, | ||
hasMultiple: function(key) { | ||
return this._map[key] instanceof Array; | ||
}, | ||
//----------------------------------- | ||
// Removal | ||
//----------------------------------- | ||
removeByKey: function() { | ||
@@ -350,3 +426,3 @@ var removed = []; | ||
for (var ix in this.keyFields) { | ||
var key2 = this.find(item, this.keyFields[ix]); | ||
var key2 = this.objectAt(item, this.keyFields[ix]); | ||
if (key2 && this._map[key2]) { | ||
@@ -379,3 +455,3 @@ var ix = this._map[key2].indexOf(item); | ||
for (var ix in this.keyFields) { | ||
var key = this.find(item, this.keyFields[ix]); | ||
var key = this.objectAt(item, this.keyFields[ix]); | ||
if (key) { | ||
@@ -411,3 +487,6 @@ var ix = this._map[key].indexOf(item); | ||
}, | ||
find: function(obj, path) { | ||
//----------------------------------- | ||
// Utility | ||
//----------------------------------- | ||
objectAt: function(obj, path) { | ||
if (typeof path === 'string') { | ||
@@ -425,2 +504,5 @@ return obj[path]; | ||
}, | ||
//----------------------------------- | ||
// Iteration | ||
//----------------------------------- | ||
forEach: function(keys, callback) { | ||
@@ -442,3 +524,3 @@ keys = keys instanceof Array ? keys : [keys]; | ||
objs.forEach(function (item) { | ||
callback(self.find(item, key), item); | ||
callback(self.objectAt(item, key), item); | ||
}); | ||
@@ -448,7 +530,14 @@ | ||
}, | ||
clone: function(callback) { | ||
//----------------------------------- | ||
// Cloning | ||
//----------------------------------- | ||
clone: function(callback, ignoreItems) { | ||
var n = new HashArray(this.keyFields.concat(), callback ? callback : this.callback); | ||
n.add.apply(n, this.all.concat()); | ||
if (!ignoreItems) | ||
n.add.apply(n, this.all.concat()); | ||
return n; | ||
}, | ||
//----------------------------------- | ||
// Mathematical | ||
//----------------------------------- | ||
sum: function(keys, key, weightKey) { | ||
@@ -459,3 +548,3 @@ var self = this, | ||
if (weightKey !== undefined) | ||
value *= self.find(item, weightKey); | ||
value *= self.objectAt(item, weightKey); | ||
@@ -479,3 +568,3 @@ ret += value; | ||
if (weightKey !== undefined) | ||
value *= (self.find(item, weightKey) / weightsTotal); | ||
value *= (self.objectAt(item, weightKey) / weightsTotal); | ||
@@ -488,2 +577,5 @@ ret += value; | ||
}, | ||
//----------------------------------- | ||
// Filtering | ||
//----------------------------------- | ||
filter: function (keys, callbackOrKey) { | ||
@@ -499,3 +591,3 @@ var self = this; | ||
function defaultCallback(item) { | ||
var val = self.find(item, callbackOrKey); | ||
var val = self.objectAt(item, callbackOrKey); | ||
return val !== undefined && val !== false; | ||
@@ -506,2 +598,5 @@ } | ||
//----------------------------------- | ||
// Operators | ||
//----------------------------------- | ||
Object.defineProperty(HashArray.prototype, 'all', { | ||
@@ -521,4 +616,7 @@ get: function () { | ||
//----------------------------------- | ||
// Browser | ||
//----------------------------------- | ||
if (typeof window !== 'undefined') | ||
window.HashArray = HashArray; | ||
},{"jclass":2}]},{},[1]); | ||
},{"jclass":1}]},{},[2]); |
@@ -6,3 +6,3 @@ { | ||
"description": "A data structure that combines a hash and an array for fast dictionary lookup and traversal by complex keys.", | ||
"version": "0.2.5", | ||
"version": "0.2.7", | ||
"main": "index.js", | ||
@@ -9,0 +9,0 @@ "url": "https://github.com/joshjung/hash-array", |
103
README.md
@@ -6,6 +6,4 @@ ![](https://nodei.co/npm/hasharray.png?downloads=True&stars=True) | ||
HashArray is a data structure that combines the best features of a hash and an array. Think of it as a super-lightweight, extensible, self-indexing database in memory. | ||
HashArray is a data structure that combines the best feature of a hash (O(1) retrieval) and an array (length and ordering). Think of it as a super-lightweight, extensible, self-indexing set database in memory. | ||
Among other things, it includes `add(...)`, `addAll(...)`, `remove(...)`, `forEach(...)` and `get(...)` operations that work for both simple keys like `'prop'` and deep keys like `['someChild', 'childProp']`. | ||
Install | ||
@@ -19,5 +17,7 @@ ======= | ||
var HashArray = require('hasharray'); | ||
var ha = new HashArray('id'); | ||
So as not to scare the faint of heart with all the technical goodness contained therein: | ||
var HashArray = require('hasharray'), | ||
ha = new HashArray('id'); | ||
ha.add({id: 'someId0', name: 'Josh'}, | ||
@@ -30,2 +30,85 @@ {id: 'someId1', name: 'Joseph'}, | ||
API | ||
=== | ||
Constructor | ||
----------- | ||
* `HashArray(keyfields, callback, options)` | ||
**`keyfields`** | ||
var HashArray = require('HashArray'); | ||
new HashArray('firstname'); // one key, depth of 1 (e.g. `item.firstname`) | ||
new HashArray(['firstname']); // same as above | ||
// one key, depth of 2 (e.g. `item.first.name`) | ||
new HashArray([['first', 'name']]); | ||
// two keys, depth of 1 (e.g. `item.firstname` AND `item.lastname`) | ||
new HashArray(['firstname', 'lastname']); | ||
// multiple keys, depth of 2 (e.g. `item.name.first` AND `item.name.last`) | ||
new HashArray([['name', 'first'], ['name', 'last']]); | ||
Insertion | ||
--------- | ||
* **`add(...items)`**: insert all arguments. | ||
* **`addAll(Array of items)`**: insert all items in the passed in Array. | ||
* **`addMap(key, item)`**: adds a single mapping from a key to a item. | ||
* **`addOne(item)`**: adds a single item, skipping dispatch of event. | ||
Retrieval | ||
--------- | ||
* **`get(key)`**: if a single item exists for `key`, returns that item. If no item exists, returns `undefined`. If multiple items exist for the key, returns an `Array`. | ||
* **`getAll(keys)`**: unions all items for all provided keys and returns an Array. Ensures no duplicates even if `keys` independently return sets that intersect. | ||
* **`getAsArray(key)`**: like `get()` except if no item exists, returns an empty `Array`. | ||
* **`sample(count, keys)`**: samples all items in the HashArray, returning a random `Array` of size `count`. If `count` is larger than the `HashArray`, returns all items in the the `HashArray` | ||
Removal | ||
------- | ||
* **`remove(...items)`**: removes all items in arguments. | ||
* **`removeByKey(...keys)`**: removes all items that match the `keys` provided. | ||
* **`removeAll()`**: clears out all items in the `HashArray` | ||
Set | ||
--- | ||
* **`intersection(HashArray)`**: returns a cloned `HashArray` whose items are the intersection between `this` and the passed in `HashArray` (`this` ^ `argument`). | ||
* **`complement(HashArray)`**: returns a cloned `HashArray` whose items are the complement between `this` and the passed in `HashArray` (`this` \ `argument`). | ||
Peeking | ||
------- | ||
* **`has(key)`**: returns `true` if any items exist for the provided key. | ||
* **`hasMultiple(key)`**: returns `true` if multiple items exist for the provided key (e.g. `get(key)` would return an `Array`) | ||
* **`collides(item)`**: returns `true` if the argument would collide with any other item in this `HashArray` for any key in the `HashArray`. | ||
Iteration | ||
--------- | ||
* **`forEach(keys, callback)`**: iterates through a union of all items that match the provided keys argument and calls the callback passing in each item as an argument. | ||
* **`forEachDeep(keys, key, callback)`**: iterates through a union of all items that match the provided keys argument and passes the value (at the provided key argument) as an argument to the callback. | ||
Mathematical | ||
------------ | ||
* **`sum(keys, key, weightKey)`**: sums all values for a union of all objects found for the `keys` argument provided at the `key` you provide. Weights the summation by `item[weightKey]` or by `1.0` if no `weightKey` is provided. | ||
* **`average(keys, key, weightKey)`**: similar to `sum()` except returns the average. | ||
Filtering | ||
--------- | ||
* **`filter(keys, callbackOrKey)`**: returns a new `HashArray` that is a clone of the current one but filtered by the provided `keys`. | ||
Utility | ||
------- | ||
* **`objectAt(item, key)`**: internally used to find a value on `item` at `key`. For example, `objectAt(obj, 'firstname')` would return `obj['firstname']`. `objectAt(obj, ['first', 'name'])` would return `obj['first']['name']`. Returns undefined if the key does not map properly to the provided object. | ||
* **`clone(callback, ignoreItems)`**: shallow clones the `HashArray`. If `ignoreItems` is true, does not clone the items just the settings. | ||
Purpose | ||
@@ -74,4 +157,4 @@ ======= | ||
Basic Usage | ||
----------- | ||
Basic Examples | ||
-------------- | ||
@@ -253,6 +336,6 @@ var HashArray = require ('hasharray'); | ||
... | ||
init: function (keyFields) | ||
init: function init(keyFields) | ||
{ | ||
console.log('My custom hash array!'); | ||
this._super(keyFields); | ||
init._super(keyFields); | ||
} | ||
@@ -275,3 +358,3 @@ ... | ||
61 passing (25ms) | ||
76 passing (25ms) | ||
@@ -278,0 +361,0 @@ License |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
30401
505
379
0