Skip to content

Instantly share code, notes, and snippets.

@toboqus
Last active December 14, 2015 08:43
Show Gist options
  • Save toboqus/5325a2594fa4fa298491 to your computer and use it in GitHub Desktop.
Save toboqus/5325a2594fa4fa298491 to your computer and use it in GitHub Desktop.
Ordered insert using binary searching for angularJS
/**
* @name orderedInsert
* @param {Array} collection
* @param {String} key
* @param {Object | array} items - array of objects to insert
* @returns {promise}
* @description will insert an object into a sorted collection using a modified
* form of binary searching. it will also insert an array of objects if that is provided
* instead.
* @example
*
* var arr = [{"id":1,"a":1},{"id":5,"a":2}];
* var items = {"id":10,"a":3} or [{"id":10,"a":3}, {"id":10,"a":3}];
*
* lo.orderedInsert(arr, items, 'id').then(function (arr){
* arr //[{"id":1,"a":1},{"id":5,"a":2},{"id":10,"a":3}]
* }, function (err){
* err
* })
*/
var orderedInsert = function orderedInsert(collection, items, key) {
var q = $q.defer();
/**
* @name insertObject
* @param collection
* @param item
* @param key
* @returns {promise}
* @description insert object into sorted array
*/
var insertObject = function insertObject(collection, item, key) {
var a = $q.defer(),
low = 0, //low value of binary search
high = collection.length - 1, //high value of binary search
i = null, //mid point
value = item[key], //value to compare to
result = collection, //collection to return
isValueNumber = (typeof value == 'number'); //true if value is number, false if not
if (collection.length == 0) { //push and resolve if collection is 0
result.push(item);
a.resolve(result);
} else {
while (low <= high) {
i = (low + high) / 2 | 0; //bitwise to floor value
var searchValue = (isValueNumber) ? parseFloat(result[i][key]) : result[i][key];
if (searchValue < value) {
if (i + 1 > high) { //if potential low is greater than high, we cant loop again and item does not exist
result.splice(i + 1, 0, item);
a.resolve(result);
} else {
low = i + 1; //low is now midpoint +1, search upper half
continue
}
} else if (searchValue > value) {
if (low > i - 1) { //if low is greater than potential high, we cant loop again and item does not exist
result.splice(i, 0, item);
a.resolve(result);
} else {
high = i - 1;
continue
}
} else {
result.splice(i, 0, item); //if item exists, splice to that index
a.resolve(result);
}
break;
}
}
return a.promise;
};
/**
*
* @param collection
* @param items
* @param key
* @returns {promise}
* @description will loop through values in the items array and insert them
*/
var insertArray = function insertArray(collection, items, key) {
var a = $q.defer(),
length = items.length,
i = -1,
result = collection;
(function insertNext(){ //function calling instead of looping as we need to make sure it waits
i++; //until object has been inserted
if(i < length) {
insertObject(result, items[i], key).then(function (arr) {
result = arr;
insertNext();
})
}else{
a.resolve(result);
}
})();
return a.promise;
};
if (angular.isArray(items)) {
insertArray(collection, items, key).then(q.resolve);
} else if (angular.isObject(items)) {
insertObject(collection, items, key).then(q.resolve)
} else {
q.reject("items must be either an object or an array of objects");
}
return q.promise;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment