Home > Software engineering >  Iterate deeply nested object values and put them in a separate variable
Iterate deeply nested object values and put them in a separate variable

Time:09-09

Let's say there is an object that looks like this:

Data object

const movies = {
  action: {
    actionMovie1: {
      title: "Action Movie 1", // <-- Move to the separate object
      rating: 5,
    },
    actionMovie2: {
      title: "Action Movie 2", // <-- Move to the separate object
      rating: 5,
    },
    actionMovie3: {
      title: "Action Movie 3", // <-- Move to the separate object
      rating: 5,
    },
  },

  adventure: {
    adventureMovie1: {
      title: "Adventure Movie 1", // <-- Move to the separate object
      rating: 5,
    },
    adventureMovie2: {
      title: "Adventure Movie 2", // <-- Move to the separate object
      rating: 5,
    },
    adventureMovie3: {
      title: "Adventure Movie 3", // <-- Move to the separate object
      rating: 5,
    },
  },

  animated: {
    new: {
      newAnimatedMovie1: {
        title: "New Animated Movie 1", // <-- Move to the separate object
        rating: 5,
      },
      newAnimatedMovie2: {
        title: "New Animated Movie 2", // <-- Move to the separate object
        rating: 5,
      },
    },
    reviewed: {
      reviewedAnimatedMovie1: {
        title: "Reviewed Animated Movie 1", // <-- Move to the separate object
        rating: 5,
      },
      reviewedAnimatedMovie2: {
        title: "Reviewed Animated Movie 2", // <-- Move to the separate object
        rating: 5,
      },
    },
  },
};

Now I'm trying to iterate a data object, collect all the movie titles and put them in a separate object so that the final result looks something like this:

Expected result

const movieTitles = {
  actionMovie1: "Action Movie 1",
  actionMovie2: "Action Movie 2",
  actionMovie3: "Action Movie 3",

  adventureMovie1: "Adventure Movie 1",
  adventureMovie2: "Adventure Movie 2",
  adventureMovie3: "Adventure Movie 3",

  newAnimatedMovie1: "New Animated Movie 1",
  newAnimatedMovie2: "New Animated Movie 2",

  reviewedAnimatedMovie1: "Reviewed Animated Movie 1",
  reviewedAnimatedMovie2: "Reviewed Animated Movie 2",
};

So far, the closest result I could get was with this method, but it only works for the first two keys.

Current attempt

const movieTitles = Object.fromEntries(
  Object.values(movies).flatMap((movie) =>
    Object.entries(movie).map(([key, value]) => [key, value.title])
  )
);

Could you please help complete this function, given the fact that more data may be added in the future. For example, later the data object might look like this:

Updated data object

const movies = {
  action: {
    actionMovie1: {
      title: "Action Movie 1",
      rating: 5,
    },
    actionMovie2: {
      title: "Action Movie 2",
      rating: 5,
    },
    actionMovie3: {
      title: "Action Movie 3",
      rating: 5,
    },
    actionMovie4: { // <-- New, follows the same structure
      title: "Action Movie 4",
      rating: 5,
    },
  },

  adventure: {
    adventureMovie1: {
      title: "Adventure Movie 1",
      rating: 5,
    },
    adventureMovie2: {
      title: "Adventure Movie 2",
      rating: 5,
    },
    adventureMovie3: {
      title: "Adventure Movie 3",
      rating: 5,
    },
    adventureMovie4: { // <-- New, follows the same structure
      title: "Adventure Movie 4",
      rating: 5,
    },
  },

  animated: {
    new: {
      newAnimatedMovie1: {
        title: "New Animated Movie 1",
        rating: 5,
      },
      newAnimatedMovie2: {
        title: "New Animated Movie 2",
        rating: 5,
      },
      newAnimatedMovie3: { // <-- New, follows the same structure
        title: "New Animated Movie 3",
        rating: 5,
      },
    },
    reviewed: {
      reviewedAnimatedMovie1: {
        title: "Reviewed Animated Movie 1",
        rating: 5,
      },
      reviewedAnimatedMovie2: {
        title: "Reviewed Animated Movie 2",
        rating: 5,
      },
      reviewedAnimatedMovie3: { // <-- New, follows the same structure
        title: "Reviewed Animated Movie 3",
        rating: 5,
      },
    },
    translated: { // <-- New category, follows the same structure
      translatedAnimatedMovie1: { // <-- New, follows the same structure
        title: "Translated Animated Movie 1",
        rating: 5,
      },
    },
  },
};

New expected result

const movieTitles = {
  actionMovie1: "Action Movie 1",
  actionMovie2: "Action Movie 2",
  actionMovie3: "Action Movie 3",
  actionMovie4: "Action Movie 4",

  adventureMovie1: "Adventure Movie 1",
  adventureMovie2: "Adventure Movie 2",
  adventureMovie3: "Adventure Movie 3",
  adventureMovie4: "Adventure Movie 4",

  newAnimatedMovie1: "New Animated Movie 1",
  newAnimatedMovie2: "New Animated Movie 2",
  newAnimatedMovie3: "New Animated Movie 3",

  reviewedAnimatedMovie1: "Reviewed Animated Movie 1",
  reviewedAnimatedMovie2: "Reviewed Animated Movie 2",
  reviewedAnimatedMovie3: "Reviewed Animated Movie 3",

  translatedAnimatedMovie1: "Translated Animated Movie 1",
};

CodePudding user response:

If you don't know what sort of possible categories there'll be, it looks like you'll need to check, when iterating over an object, whether it has a title property - and if not, then it's a new category, rather than a movie, and so you need to iterate over the whole category.

While this is possible by returning an array of entries to turn into an object, while not flattening quite all the way to keep the entry arrays, I think a more imperative recursive function would make more sense.

const movies={action:{actionMovie1:{title:"Action Movie 1",rating:5},actionMovie2:{title:"Action Movie 2",rating:5},actionMovie3:{title:"Action Movie 3",rating:5},actionMovie4:{title:"Action Movie 4",rating:5}},adventure:{adventureMovie1:{title:"Adventure Movie 1",rating:5},adventureMovie2:{title:"Adventure Movie 2",rating:5},adventureMovie3:{title:"Adventure Movie 3",rating:5},adventureMovie4:{title:"Adventure Movie 4",rating:5}},animated:{new:{newAnimatedMovie1:{title:"New Animated Movie 1",rating:5},newAnimatedMovie2:{title:"New Animated Movie 2",rating:5},newAnimatedMovie3:{title:"New Animated Movie 3",rating:5}},reviewed:{reviewedAnimatedMovie1:{title:"Reviewed Animated Movie 1",rating:5},reviewedAnimatedMovie2:{title:"Reviewed Animated Movie 2",rating:5},reviewedAnimatedMovie3:{title:"Reviewed Animated Movie 3",rating:5}},translated:{translatedAnimatedMovie1:{title:"Translated Animated Movie 1",rating:5}}}};

const movieTitles = {};
const getTitles = (parent) => {
  for (const [key, value] of Object.entries(parent)) {
    if (value.title) {
      movieTitles[key] = value.title;
    } else {
      getTitles(value);
    }
  }
};
getTitles(movies);
console.log(movieTitles);

  • Related