I am trying to write a function (that is fast and efficient) that will return the key (or array of keys if there are more than 1) of the outer-most array based on a key/value pair nested within. Something like:
function getKey(theArray, prop, val) {
// do some stuff
return key;
}
var myKey = getKey(arr, 'prop2', 'orange');
The value of myKey should be “otherKey”.
I’m pretty sure this can be done with a couple of nested for loops but these arrays are rather large and I’m thinking that, especially using jquery’s grep(), there has to be a better way… or maybe not - I’m just stumped at the moment.
One idea would be to create a look up for the objects. This is particularly useful if you have to search for a value multiple times and the values are simple things like strings AND you are looking for an exact match. Partial matches will be more difficult to achieve.
function reverseProperties(obj) {
var newObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop) &&
typeof(obj[prop]) === "string") {
if (!newObj.hasOwnProperty(obj[prop])) {
newObj[obj[prop]] = [];
}
newObj[obj[prop]].push(prop);
}
}
return newObj;
}
var arr = {};
arr['thisKey'] = { prop1 : 'a', prop2 : 'b', prop3 : 'c' };
arr['thatKey'] = { prop1 : 'x', prop2 : 'y', prop3 : 'z' };
arr['otherKey'] = { prop1 : 'red', prop2 : 'orange', prop3 : 'blue' };
var reversed = reverseProperties(arr['thisKey']);
// Then to access simply use:
console.log(reversed['a']);
//or
console.log(reversed.a);
You will, of course, have to test whether the property (value) exists before using it. You might want to write another helper function for that:
function getProperty(obj,propName) {
if (obj.hasOwnProperty(propName)) {
return obj[propName];
}
return null;
}
var properties = getProperty(reversed,'a');
To make things neater you could think about putting these functions in a namespace.
Thanks for the response. If I’m reading this properly, it looks like I have to pass the function the main array with a key name. In this case, arr[‘thisKey’]. But I am actually trying to get the function to return ‘thisKey’, based on me telling it that prop1 = a.
I’ve quickly run up the following code which does the job. It returns an array with all of the keys that contain the key/value that you ask for.
It makes good use of built-in Array methods that exist in most web browsers now. The pages for the filter and [url=“https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some”]some have compatibility code for if you want to use them on less modern browsers.
function filterKeys(obj, func) {
return Array.prototype.filter.call(Object.keys(obj), func, obj);
}
function someKeys(obj, func) {
return Array.prototype.some.call(Object.keys(obj), func, obj);
}
function atLeastOnePropertyMatches(obj, requiredProp) {
return someKeys(obj, function (prop) {
if (requiredProp.hasOwnProperty(prop)) {
return this[prop] === requiredProp[prop];
}
});
}
function getMatchingKeys(obj, requiredProp) {
return filterKeys(obj, function (prop) {
return atLeastOnePropertyMatches(this[prop], required);
});
}
var arr = {
thisKey: {prop1: 'a', prop2: 'b', prop3: 'c'},
thatKey: {prop1: 'x', prop2: 'y', prop3: 'z'},
otherKey: {prop1: 'red', prop2: 'orange', prop3: 'blue'}
},
required = {prop2: 'orange'};
results = [];
results = getMatchingKeys(arr, required);
// results is now ['otherkey']
If you just want the name of the first matching property to be returned, you could instead return just the first matching key that’s found.
function firstMatchingKey(arr, requiredProp) {
var matches = forEachKey(arr, Array.prototype.filter, function (prop) {
return atLeastOnePropertyMatches(this[prop], required);
});
return matches[0];
}
...
result = firstMatchingKey(arr, required);
// result is now 'otherkey'