SitePoint Sponsor

User Tag List

Results 1 to 5 of 5
  1. #1
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    efficient way to search a multi-dimensional array for key based on value

    I have an array that looks similar to this:

    Code:
    arr['thisKey'] = { prop1 : 'a', prop2 : 'b', prop3 : 'c' }
    arr['thatKey'] = { prop1 : 'x', prop2 : 'y', prop3 : 'z' }
    arr['otherKey'] = { prop1 : 'red', prop2 : 'orange', prop3 : 'blue' }

    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:

    Code:
    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.

    Any insight would be greatly appreciated!!

  2. #2
    SitePoint Enthusiast Anthony.Barnes's Avatar
    Join Date
    Aug 2011
    Location
    Canberra, Australia
    Posts
    80
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

    Code:
    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:

    Code:
    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.

  3. #3
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

    Am I doing something wrong?

  4. #4
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,527
    Mentioned
    84 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by daveh0 View Post
    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.

    Am I doing something wrong?
    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 some have compatibility code for if you want to use them on less modern browsers.

    Code javascript:
    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.

    Code javascript:
    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'
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  5. #5
    SitePoint Enthusiast
    Join Date
    Mar 2007
    Posts
    56
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    fantastic!! Thx!


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •