Search code examples
javascriptarraysobjectrecursion

An object whose values are arrays, whose elements may be objects. How to get the key of a value as deep as possible?


For a simple object:

const simpleObject = {
    "a": "aaa" ,
    "b": "bbb" ,
};

I know how to get the key of a value:

Object.keys(simpleObject).find(key => simpleObject[key] === "aaa");

However, if I have a complex object like this:

const complexObject = {
    "A": [  "a1", {"a2": ["a21", "a22" ]}, "a3"],   //compact representation
    "B": [                                          //expanded representation
            "b1", 
            "b2",
            {"b3": [
                    "b31", 
                    "b32"
                ]
            }
         ],
};

How to return the key of a value as deep as possible? For example:

Input Output
A A
a1 A
a2 A
a21 A.a2

I think the first step is to get the value list of all the keys:

valueList = Object.values(map1);

then using some kind of loop. But I don't know how to work it out.

In best scenario the pattern of the object can be go on, but if that's too hard then stopping the recursion at level 2 is fine.

I need a solution that works on plain JS (I'm making an automation script for Fibery). But if there is a framework I'm happy to know.


Solution

  • You could build the path when unwinding from recursion. The base case is when either the given object is the value itself, or the (non-array) object has the value as its key.

    function findValue(obj, value) {
        if (Object(obj) !== obj) return obj === value ? "." : "";
        if (!Array.isArray(obj) && Object.hasOwn(obj, value)) return ".";
        for (const [key, child] of Object.entries(obj)) {
            const path = findValue(child, value);
            if (path) return Array.isArray(obj) ? path : (key + "." + path).replace(/\.+$/, "");
        }
    }
    
    // The example from the question:
    const complexObject = {A:["a1",{a2:["a21","a22"]},"a3"],B:["b1","b2",{b3:["b31","b32"]}]};
    console.log(findValue(complexObject, "a1")); // A
    console.log(findValue(complexObject, "a2")); // A
    console.log(findValue(complexObject, "a21")); // A.a2

    Note that to be in line with your expected output, this output has no indication about the index of the array where the value was found; it just lists the keys of plain objects.

    Also, if the value happens to be a key of the top-level object, then there is no path to output. In that case this solution outputs "." so to still have a clue that the value was found.