Reputation: 585
I am working with a javascript object and although I have a solution I cant help but think it can be done more efficiently.
the object is returned from an ajax call to php script
r.price_array[1] = 39.99
r.price_array[5] = 24.99
r.price_array[10] = 19.99
and so on....
what i am doing now is searching between the key values (key values represent a quantity)
qty = $(this).val();
if (qty >= 1 && qty <= 4){
price_set = 1;
}
else if (qty >= 5 && qty <= 9){
price_set = 15;
}
else if (qty >= 10 && qty <= 14){
price_set = 25;
}
//and so on...
console.log(r.price_array[price_set]); //this returns the value
is there a way to take a quantity of 3 and find the next lowest key match which would be 1? or quantity of 7 and find key 5?
Upvotes: 4
Views: 3462
Reputation: 19
Another solution is to use a for-in loop. It has the benefice to break once the value is found.
/**
* @param {object} object - object with sorted integer keys
* @param {number} index - index to look up
*/
function getValueForLowestKey(object, index) {
let returned;
for (const key in object) {
if(key > index) break;
returned = object[key];
}
return returned;
}
Upvotes: 1
Reputation: 50797
Another approach, demonstrated in this Fiddle:
var lowerKeyFinder = function(prices) {
var keys = Object.keys(prices);
keys.sort(function(a, b) {return a - b;});
return function(val) {
var maxKey = -1;
for (var i = 0, len = keys.length; i < len; i++) {
if (maxKey < 0 || keys[i] < val) {
maxKey = Math.max(maxKey, keys[i]);
}
}
return maxKey;
};
};
var lookup = lowerKeyFinder(r.price_array);
lookup(3); //=> 1
lookup(7); //=> 5
This does not insist that the keys are initially presented in order, but sorts them once. It builds on the answer from @h2ooooooo but works a bit differently as it just offers in the end a simple function to look up by quantity.
Upvotes: 2
Reputation: 141837
Here's a function to do this. It expects to be used on objects with numeric keys like your array:
function getClosestKey(arr, target, u){
if(arr.hasOwnProperty(target))
return target;
var keys = Object.keys(arr);
keys.sort(function(a,b){ return a-b; });
// Can replace linear scan with Binary search for O(log n) search
// If you have a lot of keys that may be worthwhile
for(var i = 0, prev; i < keys.length; i++){
if(keys[i] > target)
return prev === u ? u : +prev;
prev = keys[i];
}
return +keys[i - 1];
}
You'll have to SHIM Object.keys in older browsers:
Object.keys = Object.keys || function(obj){
var result = [];
for(var key in obj)
if(obj.hasOwnProperty(key)) result.push(key);
return result;
}
Usage:
var price_array = [];
price_array[1] = 39.99;
price_array[5] = 24.99;
price_array[10] = 19.99;
getClosestKey(price_array, 0); // undefined
getClosestKey(price_array, 1); // 1
getClosestKey(price_array, 3); // 1
getClosestKey(price_array, 4); // 1
getClosestKey(price_array, 5); // 5
getClosestKey(price_array, 7); // 5
getClosestKey(price_array, 9); // 5
getClosestKey(price_array, 10); // 10
getClosestKey(price_array, 100); // 10
Upvotes: 0
Reputation: 3361
My version (tested, fiddle is here: http://jsfiddle.net/fred02138/UZTbJ/):
// assume keys in rprice object are sorted integers
function x(rprice, qty) {
var prev = -1;
var i;
for (i in rprice) {
var n = parseInt(i);
if ((prev != -1) && (qty < n))
return prev;
else
prev = n;
}
}
var rprice = {
1: 39.99,
5: 24.99,
10: 19.99
}
alert(x(rprice, 3));
alert(x(rprice, 7));
Upvotes: 2
Reputation: 39542
Sure - just use a loop:
var price_array = {
1: 39.99,
5: 24.99,
10: 19.99,
15: 15.99,
20: 10.99,
25: 5.99,
30: 0.99
}
var qty = 12;
var maxKey = -1;
for (var key in price_array) {
if (maxKey < 0 || key < qty) {
maxKey = Math.max(maxKey, key);
}
}
console.log(maxKey); //10
console.log(price_array[maxKey]); //19.99
Upvotes: 2
Reputation: 38318
You can round to the nearest multiple of 5 using Math.round()
and some simple division:
var price_array = {};
price_array[1] = 39.99;
price_array[5] = 24.99;
price_array[10] = 19.99;
function qty_round(qty) {
// Math.max() is used to enforce a minimum quantity of 1
return Math.max(1, 5 * Math.round(qty / 5));
}
console.log(price_array[qty_round(1)]); // 39.99
console.log(price_array[qty_round(4)]); // 24.99
console.log(price_array[qty_round(9)]); // 19.99
console.log(price_array[qty_round(10)]); // 19.99
With some minor modifications you could round down instead of up (using Math.floor
instead of Math.round
) or enforce a maximum quantity.
Upvotes: 0