[Medium] Implement consolidate data

March 7, 2024

☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee

Question Prompt

Imagine you're working with a reading app that tracks users' reading sessions. The app logs data in the following format:

const sessions = [
  { user: 8, duration: 50, books: ["The Hobbit"] },
  { user: 7, duration: 150, books: ["Pride and Prejudice"] },
  { user: 1, duration: 10, books: ["The Lord of the Rings"] },
  { user: 7, duration: 100, books: ["The Great Gatsby", "Animal Farm"] },
  { user: 7, duration: 200, books: ["The Great Gatsby"] },
  { user: 2, duration: 200, books: ["1984"] },
  { user: 2, duration: 200, books: ["The Great Gatsby"] },
];

Each session object has the following fields:

  • user: The user ID of the reader.
  • duration: The duration of the reading session in minutes.
  • books: An array of book titles read during the session, sorted alphabetically.

Implement a method named consolidateData that merges data from sessions for each user, providing a unified overview of their reading activities. The method should have the interface consolidateData(sessions).

Merging Rules:

  • Combine sessions for the same user into a single object.
  • Sum up the duration fields for the merged sessions.
  • Combine the books arrays, removing duplicates and sorting alphabetically.
  • Maintain the original order of the results.
  • If multiple sessions belong to the same user, the merged session should take the place of the earliest occurrence of that user in the original set.
  • Do not modify the input objects.

The expected output of the input above should be

[
  { user: 8, duration: 50, books: ["The Hobbit"] },
  {
    user: 7,
    duration: 450,
    books: ["Animal Farm", "Pride and Prejudice", "The Great Gatsby"],
  },
  { user: 1, duration: 10, books: ["The Lord of the Rings"] },
  { user: 2, duration: 400, books: ["1984", "The Great Gatsby"] },
];

Solutions

We start by creating an empty array, mergedData, which will store the final merged session objects. Additionally, we initialize a Set, seenUsers, to keep track of the user IDs we've processed. This helps in maintaining the order and ensuring that we don't process a user more than once in terms of creating a new entry.

Then, iterate over each session object in the provided sessions array. For each session, we extract the userId to determine whether it's a session from a new user or an existing one.

If the user (userId) has already been seen (i.e., it exists in the seenUsers set), we find the index of this user's data in the mergedData array. This is necessary because we need to update this specific user's consolidated data.

Once we have the index, we update the duration by adding the current session's duration to the existing total.For the books array, we merge the existing books list with the current session's books, ensuring there are no duplicates by converting it into a Set. We then convert this set back into an array and sort it to maintain a consistent order.

If the user has not been seen before, we create a new object containing the user's ID, the duration of the current session, and the books list (which we assume is unique and sorted for each session). This object is then added to the mergedData array, and the user ID is added to the seenUsers set to mark that the user has been processed.

After iterating through all session objects, we return the mergedData array, which now contains the consolidated session data for each user, with durations summed up and books lists deduplicated and sorted.

function consolidateData(sessions) {
  const mergedData = [];
  const seenUsers = new Set(); // Track seen users to maintain order

  for (const session of sessions) {
    const userId = session.user;

    // Check if user already seen
    if (seenUsers.has(userId)) {
      const existingIndex = mergedData.findIndex(
        (user) => user.user === userId
      );
      // Update existing user data
      mergedData[existingIndex].duration += session.duration;
      mergedData[existingIndex].books = Array.from(
        new Set([...mergedData[existingIndex].books, ...session.books])
      ).sort(); // Deduplicate and sort books
    } else {
      // New user, add merged data
      mergedData.push({
        user: userId,
        duration: session.duration,
        books: session.books,
      });
      seenUsers.add(userId);
    }
  }

  return mergedData;
}
☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee