indexed-map
Advanced tools
Comparing version 0.0.9 to 1.0.0
/** | ||
* IndexedMap | ||
* Copyright(c) 2013 Tobias Lindig | ||
* MIT Licensed | ||
*/ | ||
* IndexedMap | ||
* Copyright(c) 2013 Tobias Lindig | ||
* MIT Licensed | ||
*/ | ||
@@ -12,332 +12,336 @@ /** | ||
(function(){ | ||
"use strict"; //enable ECMAScript 5 Strict Mode | ||
(function() { | ||
"use strict"; //enable ECMAScript 5 Strict Mode | ||
function IndexedMap() { | ||
//ensure it called with 'new' | ||
if( !(this instanceof IndexedMap) ) { | ||
return new IndexedMap(); | ||
} | ||
function IndexedMap() { | ||
//ensure it called with 'new' | ||
if (!(this instanceof IndexedMap)) { | ||
return new IndexedMap(); | ||
} | ||
/// {Object} hash map to store the value for a key | ||
this._map = {}; | ||
/// {Array.<string>} array to store the keys in order | ||
this._list = []; | ||
} | ||
IndexedMap.prototype = { | ||
// /////////////////////////////// | ||
// properties getter | ||
/** | ||
* the count of entries | ||
*/ | ||
get length() { | ||
return this._list.length; | ||
}, | ||
/// {Object} hash map to store the value for a key | ||
this._map = {}; | ||
/// {Array.<string>} array to store the keys in order | ||
this._list = []; | ||
} | ||
IndexedMap.prototype = { | ||
// /////////////////////////////// | ||
// properties getter | ||
/** | ||
* the count of entries | ||
*/ | ||
get length() { | ||
return this._list.length; | ||
}, | ||
/** | ||
* array of keys in the current order. | ||
* | ||
* That is not a clone, it is the real keys array of the indexedMap. So do not | ||
* add, change or remove elements. That would result in an inconsistent state of indexedMap itself. | ||
* | ||
* The advantage of not cloning the key map is, that you can easily manipulate | ||
* the order of keys, if you like. So you could use the reverse or sort method of Array. | ||
*/ | ||
get keys() { | ||
return this._list; | ||
}, | ||
/** | ||
* array of keys in the current order. | ||
* | ||
* That is not a clone, it is the real keys array of the indexedMap. So do not | ||
* add, change or remove elements. That would result in an inconsistent state of indexedMap itself. | ||
* | ||
* The advantage of not cloning the key map is, that you can easily manipulate | ||
* the order of keys, if you like. So you could use the reverse or sort method of Array. | ||
*/ | ||
get keys() { | ||
return this._list; | ||
}, | ||
// /////////////////////////////// | ||
// member functions | ||
/** | ||
* checks, if given key is in map. | ||
* @return {boolean} true, if it could found otherwise false | ||
*/ | ||
has : function(key) { | ||
return this._map.hasOwnProperty(key); | ||
}, | ||
// /////////////////////////////// | ||
// member functions | ||
/** | ||
* checks, if given key is in map. | ||
* @return {boolean} true, if it could found otherwise false | ||
*/ | ||
has: function(key) { | ||
return this._map.hasOwnProperty(key); | ||
}, | ||
/** | ||
* Sort the map, that method manipulate the indexedMap. | ||
* This function is analog to the sort function of Array. | ||
* if no callback is specified, keys will be sorted lexicographically | ||
* | ||
* @param callback {function(this:IndexedMap, valueA:any, valueB:any ):number } -optional- | ||
* called in context of indexedMap | ||
* compareFunction have to return | ||
* 0 for equal, | ||
* <0 for a < b | ||
* >0 for a > b | ||
* | ||
* @return the indexedMap | ||
*/ | ||
sort : function(callback) { | ||
if(typeof(callback) === 'function') { | ||
var self = this; | ||
this._list.sort(function(a,b) { | ||
return callback.call(self, self._map[a], self._map[b]); | ||
}); | ||
} else { | ||
//sort keys lexicographically | ||
this._list.sort(); | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Sort the map, that method manipulate the indexedMap. | ||
* This function is analog to the sort function of Array. | ||
* if no callback is specified, keys will be sorted lexicographically | ||
* | ||
* @param callback {function(this:IndexedMap, valueA:any, valueB:any ):number } -optional- | ||
* called in context of indexedMap | ||
* compareFunction have to return | ||
* 0 for equal, | ||
* <0 for a < b | ||
* >0 for a > b | ||
* | ||
* @return the indexedMap | ||
*/ | ||
sort: function(callback) { | ||
if (typeof(callback) === 'function') { | ||
var self = this; | ||
this._list.sort(function(a, b) { | ||
return callback.call(self, self._map[a], self._map[b]); | ||
}); | ||
} else { | ||
//sort keys lexicographically | ||
this._list.sort(); | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Returns the first key, where callback function returns true. | ||
* | ||
* @param {function(this:IndexedMap, key:string, value:any ):boolean} callback -required- | ||
* - called for every entry in context of indexedMap. | ||
* return true will stop the search and return the value of current visited entry. | ||
* | ||
* @param {number} startIndex -optional- position to start the search, default: 0 | ||
* | ||
* @return value of first entry found | ||
* or null, if nothing found | ||
*/ | ||
find : function(callback, startIndex) { | ||
if(typeof(callback) === 'function') { | ||
var i = (typeof(startIndex) === 'number' && startIndex > 0) ? startIndex : 0; | ||
for(; i < this._list.length; ++i) { | ||
if( callback.call(this, this._list[i], this._map[this._list[i]]) === true ) { | ||
return this._map[this._list[i]]; | ||
} | ||
} | ||
} | ||
return null; | ||
}, | ||
/** | ||
* Returns the first key, where callback function returns true. | ||
* | ||
* @param {function(this:IndexedMap, key:string, value:any ):boolean} callback -required- | ||
* - called for every entry in context of indexedMap. | ||
* return true will stop the search and return the value of current visited entry. | ||
* | ||
* @param {number} startIndex -optional- position to start the search, default: 0 | ||
* | ||
* @return value of first entry found | ||
* or null, if nothing found | ||
*/ | ||
find: function(callback, startIndex) { | ||
if (typeof(callback) === 'function') { | ||
var i = (typeof(startIndex) === 'number' && startIndex > 0) ? startIndex : 0; | ||
for (; i < this._list.length; ++i) { | ||
if (callback.call(this, this._list[i], this._map[this._list[i]]) === true) { | ||
return this._map[this._list[i]]; | ||
} | ||
} | ||
} | ||
return null; | ||
}, | ||
/** | ||
* Iterate over the indexedMap. Start at given startIndex. Run until end | ||
* or the given callback returns 'false'. | ||
* | ||
* @param {function(this:IndexedMap, key:string, value:any):boolean} callback -required- | ||
* - called for every entry in context of current IndexedMap. | ||
* - stop loop from within the callback function by returning false. | ||
* @param {number} startIndex -optional- position to start the run, default: 0 | ||
* | ||
* @return the indexedMap | ||
* or null for error (missing callback) | ||
*/ | ||
each : function(callback, startIndex) { | ||
if(typeof(callback) !== 'function') { | ||
return null; | ||
} | ||
var i = (typeof(startIndex) === 'number' && startIndex > 0) ? startIndex : 0; | ||
for(; i < this._list.length; ++i) { | ||
if(callback.call(this, this._list[i], this._map[this._list[i]]) === false ) { | ||
return this; //brake | ||
} | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Iterate over the indexedMap. Start at given startIndex. Run until end | ||
* or the given callback returns 'false'. | ||
* | ||
* @param {function(this:IndexedMap, key:string, value:any):boolean} callback -required- | ||
* - called for every entry in context of current IndexedMap. | ||
* - stop loop from within the callback function by returning false. | ||
* @param {number} startIndex -optional- position to start the run, default: 0 | ||
* | ||
* @return the indexedMap | ||
* or null for error (missing callback) | ||
*/ | ||
each: function(callback, startIndex) { | ||
if (typeof(callback) !== 'function') { | ||
return null; | ||
} | ||
var i = (typeof(startIndex) === 'number' && startIndex > 0) ? startIndex : 0; | ||
for (; i < this._list.length; ++i) { | ||
if (callback.call(this, this._list[i], this._map[this._list[i]]) === false) { | ||
return this; //brake | ||
} | ||
} | ||
return this; | ||
}, | ||
/** | ||
* @return value of first entry | ||
* or null, if map is empty | ||
*/ | ||
getFirst : function() { | ||
if(this._list.length) { | ||
return this._map[this._list[0]]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value of first entry | ||
* or null, if map is empty | ||
*/ | ||
getFirst: function() { | ||
if (this._list.length) { | ||
return this._map[this._list[0]]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value of last entry | ||
* or null, if map is empty | ||
*/ | ||
getLast : function() { | ||
if(this._list.length) { | ||
return this._map[this._list[this._list.length-1]]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value of last entry | ||
* or null, if map is empty | ||
*/ | ||
getLast: function() { | ||
if (this._list.length) { | ||
return this._map[this._list[this._list.length - 1]]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value from entry next to given key | ||
* or null, if key has no next | ||
*/ | ||
getNextOf : function(key) { | ||
var nextKey = this.nextKeyOf(key); | ||
if(nextKey) { | ||
return this._map[nextKey]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value from entry next to given key | ||
* or null, if key has no next | ||
*/ | ||
getNextOf: function(key) { | ||
var nextKey = this.nextKeyOf(key); | ||
if (nextKey) { | ||
return this._map[nextKey]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value from entry previous to given key | ||
* or null, if key has no previous | ||
*/ | ||
getPrevOf : function(key) { | ||
var prevKey = this.prevKeyOf(key); | ||
if(prevKey) { | ||
return this._map[prevKey]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value from entry previous to given key | ||
* or null, if key has no previous | ||
*/ | ||
getPrevOf: function(key) { | ||
var prevKey = this.prevKeyOf(key); | ||
if (prevKey) { | ||
return this._map[prevKey]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return key from entry next to given key | ||
* or null, if key has no next | ||
*/ | ||
nextKeyOf : function(key) { | ||
if(this.has(key)) { | ||
return this._list[this._list.indexOf(key)+1]; | ||
} | ||
else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return key from entry next to given key | ||
* or null, if key has no next | ||
*/ | ||
nextKeyOf: function(key) { | ||
if (this.has(key)) { | ||
return this._list[this._list.indexOf(key) + 1]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return key from entry previous to given key | ||
* or null, if key has no previous | ||
*/ | ||
prevKeyOf : function(key) { | ||
if(this.has(key)) { | ||
return this._list[this._list.indexOf(key)-1]; | ||
} | ||
else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return key from entry previous to given key | ||
* or null, if key has no previous | ||
*/ | ||
prevKeyOf: function(key) { | ||
if (this.has(key)) { | ||
return this._list[this._list.indexOf(key) - 1]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value for given key | ||
* or null, if key was not found | ||
*/ | ||
get : function(key) { | ||
if( this.has(key) ) { | ||
return this._map[key]; | ||
} | ||
else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value for given key | ||
* or null, if key was not found | ||
*/ | ||
get: function(key) { | ||
if (this.has(key)) { | ||
return this._map[key]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* @return value at given index | ||
* or null, if index was not found | ||
*/ | ||
getAt : function(index) { | ||
return this.get(this._list[index]); | ||
}, | ||
/** | ||
* @return value at given index | ||
* or null, if index was not found | ||
*/ | ||
getAt: function(index) { | ||
return this.get(this._list[index]); | ||
}, | ||
/** | ||
* Overwrite the value for the given key. | ||
* | ||
* @return old value | ||
* or null, if key was not found. | ||
* | ||
*/ | ||
set : function(key, value) { | ||
if( this.has(key) ) { | ||
var oldValue = this._map[key]; | ||
this._map[key] = value; | ||
return oldValue; | ||
} | ||
else { | ||
return null; | ||
} | ||
}, | ||
/** | ||
* Overwrite the value for the given key. | ||
* | ||
* @return old value | ||
* or null, if key was not found. | ||
* | ||
*/ | ||
set: function(key, value) { | ||
if (this.has(key)) { | ||
var oldValue = this._map[key]; | ||
this._map[key] = value; | ||
return oldValue; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
setAt : function(index, value) { | ||
return this.set(this._list[index], value); | ||
}, | ||
setAt: function(index, value) { | ||
return this.set(this._list[index], value); | ||
}, | ||
/** | ||
* Insert new element before the referenced element targetKey. | ||
* If reference is null or not found, new element is inserted at the end | ||
* of the list. | ||
* | ||
* @return value for key | ||
* or null if !key or key always used | ||
*/ | ||
insert : function(key, value, targetKey) { | ||
return this.insertAt(key, value, this._list.indexOf(targetKey)); | ||
}, | ||
/** | ||
* Insert new element before the referenced element targetKey. | ||
* If reference is null or not found, new element is inserted at the end | ||
* of the list. | ||
* | ||
* @return value for key | ||
* or null if !key or key always used | ||
*/ | ||
insert: function(key, value, targetKey) { | ||
return this.insertAt(key, value, this._list.indexOf(targetKey)); | ||
}, | ||
insertAt : function(key, value, targetIndex) { | ||
if(!key || this.has(key) ) { | ||
//no key or key is used | ||
return null; | ||
} | ||
insertAt: function(key, value, targetIndex) { | ||
if (!key || this.has(key)) { | ||
//no key or key is used | ||
return null; | ||
} | ||
this._map[key] = value; | ||
if(typeof(targetIndex) !== 'number' || targetIndex < 0 || targetIndex >= this._list.length) { | ||
//add to end | ||
this._list.push(key); | ||
return this._map[key]; | ||
} else { | ||
//add to target position | ||
this._list.splice(targetIndex, 0, key); | ||
return this._map[key]; | ||
} | ||
}, | ||
this._map[key] = value; | ||
if (typeof(targetIndex) !== 'number' || targetIndex < 0 || targetIndex >= this._list.length) { | ||
//add to end | ||
this._list.push(key); | ||
return this._map[key]; | ||
} else { | ||
//add to target position | ||
this._list.splice(targetIndex, 0, key); | ||
return this._map[key]; | ||
} | ||
}, | ||
/** | ||
* Move the key to position of targetKey by inserting key before targetKey. | ||
* If targetKey is not found, key will be moved to the end. | ||
* | ||
* @return value for key | ||
* or null if key was not found | ||
*/ | ||
move : function(key, targetKey) { | ||
if( !this.has(key) ) { | ||
return null; | ||
} | ||
/** | ||
* Move the key to position of targetKey by inserting key before targetKey. | ||
* If targetKey is not found, key will be moved to the end. | ||
* | ||
* @return value for key | ||
* or null if key was not found | ||
*/ | ||
move: function(key, targetKey) { | ||
if (!this.has(key)) { | ||
return null; | ||
} | ||
//remove only the key, not the value! | ||
var index = this._list.indexOf(key); | ||
this._list.splice(index, 1); | ||
//remove only the key, not the value! | ||
var index = this._list.indexOf(key); | ||
this._list.splice(index, 1); | ||
//if targetKey not found, we get -1, that is safe for splice it will work at the end | ||
var targetIndex = this._list.indexOf(targetKey); | ||
this._list.splice(targetIndex, 0, key); | ||
//if targetKey not found, we get -1, that is safe for splice it will work at the end | ||
var targetIndex = this._list.indexOf(targetKey); | ||
this._list.splice(targetIndex, 0, key); | ||
return this._map[key]; | ||
}, | ||
return this._map[key]; | ||
}, | ||
moveAt : function(index, targetIndex) { | ||
this.move(this._list[index], this._list[targetIndex]); | ||
}, | ||
moveAt: function(index, targetIndex) { | ||
this.move(this._list[index], this._list[targetIndex]); | ||
}, | ||
/** | ||
* Remove the entry for the given key. | ||
* | ||
* @return old value | ||
* or null, if key was not found. | ||
*/ | ||
remove : function(key) { | ||
if(!this.has(key)) { | ||
//key is not found | ||
return null; | ||
} | ||
/** | ||
* Remove the entry for the given key. | ||
* | ||
* @return old value | ||
* or null, if key was not found. | ||
*/ | ||
remove: function(key) { | ||
if (!this.has(key)) { | ||
//key is not found | ||
return null; | ||
} | ||
var oldValue = this._map[key]; | ||
delete this._map[key]; | ||
var index = this._list.indexOf(key); | ||
this._list.splice(index, 1); | ||
var oldValue = this._map[key]; | ||
delete this._map[key]; | ||
var index = this._list.indexOf(key); | ||
this._list.splice(index, 1); | ||
return oldValue; | ||
}, | ||
return oldValue; | ||
}, | ||
removeAt : function(index) { | ||
return this.remove(this._list[index]); | ||
} | ||
}; | ||
removeAt: function(index) { | ||
return this.remove(this._list[index]); | ||
} | ||
}; | ||
/** | ||
* make class IndexedMap public | ||
*/ | ||
exports = module.exports = IndexedMap; | ||
})();//close strict mode | ||
/** | ||
* make class IndexedMap public | ||
*/ | ||
if(typeof define === 'function' && define.amd) { | ||
//as AMD module | ||
define('indexed-map', IndexedMap); | ||
} else if(typeof module === 'object' && typeof define !== 'function') { | ||
//as node module | ||
exports = module.exports = IndexedMap; | ||
} else if(window) { | ||
// as global class to window | ||
window.IndexedMap = IndexedMap; | ||
} | ||
})(); //close strict mode |
{ | ||
"name": "indexed-map", | ||
"version": "0.0.9", | ||
"description": "A map that maintains the order of entries. Give access to entries by index or key.", | ||
"version": "1.0.0", | ||
"description": "An enhanced map that supports easy insertion or deletion at specific position. Give access to entries by index or key. Can be used instead of a linked list.", | ||
"keywords": [ | ||
"list", "map", "array", "collection", "doubly-linked", | ||
"linkedmap", "sorted", "ordered", "indexed", "vector" | ||
"linked", "list", "map", "array", "collection", "doubly-linked", | ||
"linkedlist", "linkedmap", "sorted", "ordered", "indexed", "vector" | ||
], | ||
@@ -36,2 +36,2 @@ "author": { | ||
} | ||
} | ||
} |
@@ -1,13 +0,13 @@ | ||
# IndexedMap | ||
# IndexedMap [![Build Status](https://travis-ci.org/tlindig/indexed-map.png?branch=master)](https://travis-ci.org/tlindig/indexed-map) | ||
A map that maintains the order of entries. Give access to entries by index or key. | ||
Keys have to be unique in map. | ||
An enhanced map that supports easy insertion or deletion at specific position. Give access to entries by index or key. Can be used instead of a linked list. | ||
``` | ||
Stability: 3 Stable | ||
Stability: 4 - API Frozen | ||
``` | ||
(Stability Index: http://nodejs.org/api/documentation.html#documentation_stability_index) | ||
( see [Stability Index](http://nodejs.org/api/documentation.html#documentation_stability_index) ) | ||
## Install | ||
as node module with npm: | ||
```bash | ||
@@ -19,4 +19,6 @@ npm install indexed-map --production | ||
Can be used as node module 'indexed-map', as AMD module 'indexed-map' or as global class at `window.IndexedMap`. | ||
```js | ||
var IndexedMap = require('indexed-map') | ||
var IndexedMap = require('indexed-map'); | ||
var myMap = IndexedMap(); | ||
@@ -27,3 +29,4 @@ // add an entry at the end | ||
Keys have to be of type 'string', values can by any type, there is no restrictions. | ||
Keys have to be of type 'string' and unique in map. | ||
Values can by any type, there is no restrictions. | ||
@@ -30,0 +33,0 @@ Some methods supported in two versions, one with key as reference and the |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
25134
11
461
1
195