Home > OS >  Fast and performance based way to merge objects from three arrays onto one object in javascript
Fast and performance based way to merge objects from three arrays onto one object in javascript

Time:01-06

I have an array of objects that has a few properties in javascript that has a basic structure like so:

{
  id: 123-456
  username: sdfjweihg
}

then I have three, very large arrays that are unsorted, all of them are arrays of objects, but the objects all have all sorts of different matching fields, however they all have an acccount_id that matches the id from the above object.

The above objects also come in an array, so I was doing something like:

let fullUsers = [];
for(let i = 0; i < users.length; i  ) {
   fullUser.push({
      user: users[i],
      favorite_movie: moviesOfusers.filter((movie) => movie.account_id === users[i].id),
      favorite_toys: toysOfusers.filter((toy) => toy.account_id === users[i].id),
      favorite_colors: colorsOfUsers.filter((color) => color.account_id === users[i].id)
   )};
}

Where moviesOfusers, toysOfUsers and colorsOfUsers are the arrays that have all sorts of other properties on them, but that matching account_id. It works, and does what I want, but I need something less CPU intensive and faster. If anyone has any suggestions to achieve the same search and attaching that's better I'd love some new ideas. Thank you!

CodePudding user response:

Best you can do is reduce each of the large arrays in a single iteration each to a map...

const colorsByAccountId = colorsOfUsers.reduce((acc,color) => {
   const { account_id } = color
   if(acc[account_id]) {
     acc[account_id].push(color)
   } else {
     acc[account_id] = [color]
   }
   return acc
},{})

and then...

const fullUsers = users.map((user) => ({
   user,
   colors: colorsByAccountId[user.id] || [],
   ...other stuff
})

Not sure if that'll get you enough of a gain or not.

CodePudding user response:

You can precompute bookkeeping arrays of account IDs to movies, toys, and cars:

const userToMovie = {}
const userToToy = {}
const userToColor = {}
moviesOfusers.forEach(movie => { userToMovie[movie.account_id] = movie })
toysOfusers.forEach(toy => { userToToy[toy.account_id] = toy })
colorsOfUsers.forEach(color => { userToColor[color.account_id = color })

let fullUsers = [];
for(let i = 0; i < users.length; i  ) {
   fullUsers.push({
      user: users[i],
      favorite_movie: userToMovie[users[i].id],
      favorite_toys: userToToy[users[i].id],
      favorite_colors: userToColor[users[i].id]
   )};
}

CodePudding user response:

Personally I would only map the users into a keyed set and then use that to loop over the other items. This way

  • You loop over the users once (reduce)
  • You loop over each data set once (forEach X each dataset)
  • You look over the values of the object once. (Object.keys)

/* Data */

const users = [
  {id: 1, name: 'Bob'}, 
  { id: 2, name: 'Al' }
];

const toys = [
  { id:1, name: 'foo'},
  { id:1, name: 'bar'},
  { id:2, name: 'baz'}
];

const books = [
  {id: 1, name: 'book1'}
]

/* First step, make the easy loop up by id for the users */
const mappedById = users.reduce((acc, user) => {
  acc[user.id] = {
    user,
    toys: [],
    books: []
  };
  return acc;
}, {});

/* Simple function what will append the item to the array */
const setUserData = (mappedById, items, key) => {
  items.forEach(item => mappedById[item.id] ? .[key] ? .push(item))
}

/* Look over the sub data sets */
setUserData(mappedById, toys, 'toys');
setUserData(mappedById, books, 'books');

/* Get the final array out of the users */
const result = Object.values(mappedById);

console.log(result);

Other way is to map all of the data sources and combine them when you loop over the users.

  • Loop over each dataset (reduce X each dataset)
  • Loop over the user dataset (forEach)

/* Data */
const users = [
  {id: 1, name: 'Bob'}, 
  { id: 2, name: 'Al' }
];

const toys = [
  { id:1, name: 'foo'},
  { id:1, name: 'bar'},
  { id:2, name: 'baz'}
];

const books = [
  {id: 1, name: 'book1'}
]


// Function to build array by user id for the sub data
const setUserData = (acc, item) => {
  acc[item.id] = acc[item.id] || [];
  acc[item.id].push(item);
  return acc;
}

/* Look over the sub data sets */
const toysMapped = toys.reduce(setUserData, {});
const booksMapped = books.reduce(setUserData, {});


/* Build the user array with the sub data */
const result = users.map((user) => ({
  user,
  toys: toysMapped[user.id] || [],
  books: booksMapped[user.id] || []
}));

console.log(result);

  • Related