简体   繁体   中英

How to find a property within nested array and return its location

Using javascript only, is there a way to locate a property within an array that is itself within another array and return its "path"?

Imagine a hierarchical group of nested arrays much like this example:

    var bigBox = [  

        mediumBoxA = [
                smallBoxA = [                  
                         toyA = { toyId : "Blue Ball"},
                         toyb = { toyId : "Pink Ball"}
                    ],

                smallBoxB = [                  
                         toyA = { toyId : "Girl Doll"},
                         toyB = { toyId : "Boy Doll"}
                    ],
            ],

        mediumBoxB = [
                smallBoxA = [                  
                         toyA = { toyId : "Batman"},
                         toyB = { toyId : "Superman"}
                    ],

                smallBoxB = [                  
                         toyA = { toyId : "Lego"},
                         toyB = { toyId : "Soldier"}
                    ],
            ]

   ];

Given that, in the console I want to be able to search for example: "Batman" and get that it is located in bigBox > mediumBoxB > smallBoxA > toyA. Again, I'm looking for a JS only solution and something I can implement on the console. No HTML involved.

Now, I know that i could go only by the index number, I used labels on each array such as "smallBox", "toyB", etc.. for explanation purposes.

Thank you guys!

I've implemented a recursive function, which finds the path and returns it as an array:

/**
 * Finds an value and returns the path of nested variable names
 * 
 * @param {obj}       The object to search in
 * @param {search}    The value to search for
 * @param {variables} The relevant variables names or the context object
 * @param {context}   The context object in which to search the variable names
 *
 * @return The found path as an array or null if nothing was found
 */
function getPath(obj, search, variables, context) {

    if(context === undefined) {
        context = window;        
    }

    if(variables === undefined) {
        variables = window;
    }
    if(!Array.isArray(variables)) {
        // if variables is an object, this object is the context
        context = variables;
        // copy the keys to the variables array
        variables = [];
        for(var key in context) {
            if(context.hasOwnProperty(key)) {
                try {
                    // try to read property
                    context[key];
                    // push key to variable names
                    variables.push(key);
                } catch(e) {
                    // some properties of the window object cannot be read
                }
            }
        }
    }

    function getVariableName(variable) {
        for(var i = 0; i < variables.length; i++) {
            var name = variables[i];
            if(context[name] === variable) {
                // return variable name
                return name;
            }
        }
        return null;
    }

    function _getPath(variable, path) {
        if(typeof variable === 'object') {
            var name = getVariableName(variable);
            if(name) {
                var pathCopy = path.slice(0);
                pathCopy.push(name);
                for(var key in variable) {
                    // recursive call of _getPath
                    var returnedPath = _getPath(variable[key], pathCopy);
                    if(returnedPath) {
                        return returnedPath;
                    }
                }
            }            
        } else if(variable === search) {
            return path;
        }
        // if nothing was found, return null
        return null;
    }

    // now recursively search for the value
    return _getPath(obj, []);
}

With the function getPath you can do the following:

var path = getPath(bigBox, "Batman");
console.log(path.join(" > ")); // logs "bigBox > mediumBoxB > smallBoxC > toyE"

If all of your variables are in one object, you can also call the getPath function with an additional context argument like this:

var path = getPath(context.bigBox, "Batman", context);



I've changed the object bigBox a little bit, so that every variable is exactly once in the object.

Here is the jsFiddle demo

Yes, you can walk through the tree using enumeration, and get the name of each key by simply using the for x in y syntax. In each iteration, the key's name is in the value of X. You can use your own preferred recursive or iterative implementation for scanning the tree and constructing a search path, then return the built path once you find your matching value.

That's the naive implementation in any case. There might be some faster ways to do tree searches; I'm not a computer scientist.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM