Home > OS >  How to recursively iterate through a nested object for a specific key
How to recursively iterate through a nested object for a specific key

Time:02-02

I am trying to write a recursive function that essentially drills down an object looking for a specific key. Once that key is found I would like to rename that object key and keep the original contents and continue to iterate through that found key's value (array of objects) looking for the same key if present.

const data = {
   "name": "lorem",
   "folders": [
      {
         "name": "ipsum",
         "folders": [
            {
               "name": "inner ipsum",
               "folders": [
                   {
                      "name": "first nested"
                   },
                   {
                      "name": "second nested" 
                   }
               ]
            }
         ]
      },
      {
         "name": "dolor",
         "folders": [
            {
               "name": "first inner dolor"
            },
            {
               "name": "second inner dolor",
               "folders": [
                  {
                     "name": "test"
                  }
               ]
            }
         ]
      }
   ]
   
}

// recursive function that looks for key === "folders" within obj and renames to "items"
// continues to search within "items" value for the same "folders" key to repeat the process of // renaming the obj

const recursivelyGetAllFolders = (obj) => {
   for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (key === "folders") {
          // keep contents of folders obj, but rename key to "items"
          obj["items"] = obj["folders"];

          // call function recursively to iterate through again?
          if (obj["items"] && typeof obj["items"] === "object") {
            const result = recursivelyGetAllFolders(folder["items"]);
            if (result) {
               return result;
            }
          } else {
              return obj;
          }
        }
      }
    }
}

recursivelyGetAllFolders(data);

CodePudding user response:

You don't have to loop through the keys of object. You just need to

  • check if the object has the folders key and rename it to items.
  • And then recursively call the function on each object in items (You are recursively calling on the items array itself instead of each object in the array)
function recursivelyUpdateFolders(obj) {
  if (obj.hasOwnProperty("folders")) {
    obj.items = obj.folders
    delete obj.folders
    obj.items?.forEach(recursivelyUpdateFolders)
  }
  return obj
}

Here's a snippet:

const data={name:"lorem",folders:[{name:"ipsum",folders:[{name:"inner ipsum",folders:[{name:"first nested"},{name:"second nested"}]}]},{name:"dolor",folders:[{name:"first inner dolor"},{name:"second inner dolor",folders:[{name:"test"}]}]}]};

function recursivelyUpdateFolders(obj) {
  if (obj.hasOwnProperty("folders")) {
    obj.items = obj.folders
    delete obj.folders
    obj.items?.forEach(recursivelyUpdateFolders)
  }
  return obj
}

console.log(
  recursivelyUpdateFolders(data)
)

CodePudding user response:

We can take one step back and make "folders" and "items" parameters to a function. It won't make our code any more difficult, but will make it more flexible.

This version does not mutate your original (we're not barbarians, right?), but returns a copy with the changes applied.

const renameNestedKey = (source, target) => (o) =>
  Array .isArray (o) 
    ? o .map (renameNestedKey (source, target))
  : Object (o) === o
    ? Object .fromEntries (Object .entries (o) .map (
        ([k, v]) => [k == source ? target : k, renameNestedKey (source, target) (v)] 
      ))
  : o

const data = {name: "lorem", folders: [{name: "ipsum", folders: [{name: "inner ipsum", folders: [{name: "first nested"}, {name: "second nested"}]}]}, {name: "dolor", folders: [{name: "first inner dolor"}, {name: "second inner dolor", folders: [{name: "test"}]}]}]}

console .log (renameNestedKey ('folders', 'items') (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

Our function takes source and target key names and returns a function that takes an input object. When the input is an array, it maps itself over that array. When the input is an object, we tear it apart into key-value pairs, then map over those, converting the key when necessary, and recurring on the value, then puts the resulting set of key-value pairs back into an object. When the input is neither an array nor an object, we simply return it.

  • Related