Last active
December 14, 2015 08:43
-
-
Save toboqus/5325a2594fa4fa298491 to your computer and use it in GitHub Desktop.
Ordered insert using binary searching for angularJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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