简体   繁体   中英

Logically merge arrays in javascript

I have some data of a single entity being distributed across multiple tables in a mysql database. When I fetch this data, I end up with separate arrays containing data of the same logical entity. So I want to logically merge these separate arrays for ease to work with it on my app. A simpler example would be:

arrays:

cakes = [
          {id: 1, name: 'A'},
          {id: 2, name: 'B'},
          {id: 3, name: 'C'}
         ]

flavours = [
             {id: 1, cakeId: 2, flavour: 'mint'},
             {id: 2, cakeId: 2, flavour: 'strawberry'},
             {id: 3, cakeId: 3, flavour: 'mint'}
           ]

The goal is to merge these two arrays into a single array, respecting the reference to the cake array (cakeId) in the flavours array. The final array I would expect in this example would be:

newCakesArray = [
                 {id: 1, name: 'A'},
                 {id: 2, name: 'B', flavours: {id: 1, cakeId: 2, flavour: 'mint'},
                                              {id: 2, cakeId: 2, flavour: 'strawberry'}},
                 {id: 3, name: 'C', flavours: {id: 3, cakeId: 3, flavour: 'mint'}}
                ]

I appreciate any help.

var cakes = [
          {id: 1, name: 'A'},
          {id: 2, name: 'B'},
          {id: 3, name: 'C'}
         ];

var flavours = [
             {id: 1, cakeId: 2, flavour: 'mint'},
             {id: 2, cakeId: 2, flavour: 'strawberry'},
             {id: 3, cakeId: 3, flavour: 'mint'}
           ];

// let's create an index table based on the id field.
var cakesObs = {};
for (var cake of cakes) {
  cakesObs[cake.id] = Object.assing({}, cake); // cloning cake to avoid  changes in the original object
  cakesObs[cake.id].flavours = []; // an empty array by default.
}

// adding flavours to the index table
for (var flavour of flavours) {
  cakesObs[flavour.cakeId].flavours.push(flavour);
}

// converting the table back to an array of cakes but now with flavours.
var newCakesArray = Object.values(cakesObs);

You can iterate over cakes array and add "flavours" property. For checking which objects in flavours array should be added, use "filter" function.

for (const i in cakes) {
  const cakeId = cakes[i].id;
  cakes[i].flavours = flavours.filter(f => f.cakeId === cakeId)
}

If you are not sure about ordering in both arrays you can do something like this:

cakes.map(cake => {
   const flavours = flavours.find(f => f.cakeId === cake.id);
   if(flavours) return {
     ...cake,
     flavours
   }
  return cake;
})

If you worry about space complexity and don't want to create another array you can do it in place

for(let i=0;i<cakes.length;i++) {
    const flavours = flavours.find(f => f.cakeId === cake.id);
    if(flavours) cakes[i].flavours = flavours;
}

In order to reduce the time complexity associated with searching for correct cakeId within flavors objects (the search is made in every iteration that is very expensive), you should have flavors sorted by cakeId and then binary search on cakeId. It will be nlogn complexity instead of n**2 .

Use reduce to iterate over the cakes array. Inside call back function use filter to get the objects from flavors by matching id & cakeId . If the accumulator object have and key by same as cake id then update or create the flavour key. After iteration use Object.values to get the final array

 let cakes = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }, { id: 3, name: 'C' } ] let flavours = [{ id: 1, cakeId: 2, flavour: 'mint' }, { id: 2, cakeId: 2, flavour: 'strawberry' }, { id: 3, cakeId: 3, flavour: 'mint' } ] let newData = cakes.reduce((acc, curr) => { let getFlavours = flavours.filter(item => item.cakeId === curr.id); if (.acc[curr.id]) { acc[curr;id] = curr. } if (getFlavours.length > 0) { acc[curr.id];flavours = getFlavours } return acc, }. {}) console.log(Object.values(newData))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM