Let say if I have an object like this
resourceMap = {
"a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"b": [11, 12],
"c": [21, 23],
"d": [54, 55, 56, 57, 510]
};
What is the best way to figure out if resourceId = 21
would be "c"
?
We don't know the key names or number of keys. It only matches once: meaning 21
will belong to only one key "c"
.
I am thinking of looping through all keys and do indexOf()
, but I don't feel it's "elegant" enough.
I could use Underscore but try to avoid and go with what Angular or jQuery or just vanilla Javascript.
Let say if I have an object like this
resourceMap = {
"a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"b": [11, 12],
"c": [21, 23],
"d": [54, 55, 56, 57, 510]
};
What is the best way to figure out if resourceId = 21
would be "c"
?
We don't know the key names or number of keys. It only matches once: meaning 21
will belong to only one key "c"
.
I am thinking of looping through all keys and do indexOf()
, but I don't feel it's "elegant" enough.
I could use Underscore but try to avoid and go with what Angular or jQuery or just vanilla Javascript.
Share Improve this question edited Oct 7, 2014 at 19:58 HP. asked Oct 7, 2014 at 17:10 HP.HP. 19.9k56 gold badges159 silver badges258 bronze badges 5- Are the numbers in the arrays distinct, or is it possible that a number reverse-maps to more than a single item? – spender Commented Oct 7, 2014 at 17:12
- Either you pre-process it to be in a different format or you loop on demand. Either way Vanilla JS or underscore, you will end up doing the same thing under the covers. – epascarello Commented Oct 7, 2014 at 17:13
- @spender says it right in the OPs question. "It only matches once:..." – epascarello Commented Oct 7, 2014 at 17:13
- @spender the number only occurs once in each key or in all the keys. – HP. Commented Oct 7, 2014 at 17:15
- Why is there "JSON" in the header? – Teemu Commented Oct 7, 2014 at 17:20
5 Answers
Reset to default 10It's perfectly acceptable to have numeric property names for objects in JavaScript. We can use this to our advantage to build a second object that maps everything in reverse. This will make lookups inexpensive.
var reverseMap = {};
for(var propName in resourceMap)
{
var numsArr = resourceMap[propName];
numsArr.forEach(function(num){
reverseMap[num]=propName;
});
}
console.log(reverseMap[54]); //'d'
http://jsfiddle.net/y11sbgbv/
Building the reverseMap can also be done more "functionally" (e.g. without using side-effects) as follows:
var reverseMap2 = Object.keys(resourceMap).reduce((acc, propName) =>
resourceMap[propName].reduce((a, num) => {
a[num] = propName;
return a;
}, acc), {});
Preprocess into a different look up table
var revMap = []; // or var revMap = {};
Object.keys(resourceMap).forEach(function(key) {
resourceMap[key].forEach( function (ind) {
revMap[ind] = key;
});
});
console.log(revMap[21])
or look up on demand:
resourceMap = { "a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "b": [11, 12], "c": [21, 23], "d": [54, 55, 56, 57, 510] };
function findMapKey (map, ind) {
var match = null;
Object.keys(map).some(function(key) {
var test = map[key].indexOf(ind)!==-1;
if (test) {
match = key;
}
return test;
});
return match;
}
console.log(findMapKey(resourceMap, 21));
It looks like values are sorted, so you can first look if the latest of each array is greater than the value you're searching for, once you find it, look for the value itself.
for(var propName in resourceMap)
{
var array = resourceMap[propName];
var lastNum = array[array.length-1];
if(lastNum == 21 || (lastNum > 21 && array.indexOf(21) > -1))
{
console.log(propName)
break;
}
}
Unless you're working with a massive amount of data, your idea is fine:
var resourceMap = {
"a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"b": [11, 12],
"c": [21, 23],
"d": [54, 55, 56, 57, 510]
};
/**
* @return resource's group, or false if no matching group is found
*/
var getResourceGroup = function(res) {
for (var i in resourceMap) {
if (resourceMap[i].indexOf(res) > -1) {
return i;
}
}
return false;
}
console.log(getResourceGroup(21));
I understand the desire for elegance, and I strive for that in my own work as well. But this is simple, easily supported, and relatively fast assuming your data set isn't huge.
If you're going to call the function multiple times, it might be worth building out the reverse dictionary the first time through the function, so that you can use that to speed up future lookups. The catch there is that if you do have a ton of data, you're going to build a fairly large data structure in memory. Probably not a big deal, but worth considering.
Try
resourceMap = {
"a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"b": [11, 12],
"c": [21, 23],
"d": [54, 55, 56, 57, 510]
};
var getKey = function(val, _key) {
$.each(resourceMap, function(k, v) {
if ($.inArray(val, v) != -1) {
_key = k
}
})
return _key
};
getKey(21)
jsfiddle http://jsfiddle.net/guest271314/gbnzmq51/