0

I have been trying to merge the following two objects to produce the results (all shown below). I am having a hard time coming up with a solution without using so many loops. If anyone can help me I would appreciate it.

var arr1 = [
    { parent: 1, child: 1, status: 'something', active: true },
    { parent: 1, child: 2, status: 'some other thing', active: true },
    { parent: 900, child: 1, status: 'something', active: true },
    { parent: 906, child: 1, status: 'nothing', active: true }
];


var arr2 = [
    { parent: 1, child: 1, location: 'there' },
    { parent: 1, child: 2, location: 'here' },
    { parent: 1, special: false },
    { parent: 900, child: 1, location: 'here' },
    { parent: 900, special: true },
    { parent: 905, child: 1, location: 'everywhere' },
    { parent: 905, special: true }
];

// result should be:
/* 
 
  result: [{parent: 1, child: 1, status: 'something', active: true, location: 'there'},
           {parent: 1, child: 1, status: 'some other thing', active: true, location: 'here'},
           {parent: 900, child: 1, status: 'something', active: true, location: 'here'},
           { parent: 905, child: 1, location: 'everywhere'},
           { parent: 906, child: 1, status: 'nothing', active: true}
          ]
  randos: [{parent: 1, special: false},
           {parent: 900, special: true},
           {parent: 905, special: true}
          ]
*/

function fmMerge(arr1, arr2) {
    const result = [];
    const randos = [];

    let outerArray;
    let innerArray;

    if (arr1.length >= arr2.length) {
        outerArray = arr1;
        innerArray = arr2;
    } else {
        outerArray = arr2;
        innerArray = arr1;
    }
    for (let i = 0; i < outerArray.length; i++) {
        const obj1 = outerArray[i];
        for (let j = 0; j < innerArray.length; j++) {
            const obj2 = innerArray[j];
            const copy = Object.assign({}, obj2);
            if ((obj1.parent && obj1.child) || (obj2.parent && obj2.child)) {
                if ((obj1.parent === obj2.parent) && (obj1.child === obj2.child)) {
                    const mergedObj = Object.assign(copy, obj1);
                    result.push(mergedObj);
                }
              } else if ((obj1.parent && !obj1.child) || (obj2.parent && !obj2.child)) {
                if (obj2.parent && !obj2.child && !randos.includes(obj2)) {
                    randos.push(obj2);
                }

                if (obj1.parent && !obj1.child && !randos.includes(obj1)) {
                    randos.push(obj1);
                }
            }
        }
    }
    return {
        result: result,
        randos: randos
    }
}

const result = fmMerge(arr1, arr2);

const index = {};

result['result'].forEach(obj => {
    if (index[obj.parent]) {
        const array = index[obj.parent];
        array.push(obj);
    } else {
        index[obj.parent] = [obj]
    }
});

console.log(result);

Essentially I want to merge objects from two arrays if their parent and child are equal. However, if not then I would like to just place value in the array. For the values that don't have a child I would like to push into a separate array.

The result I want is in the comments in the code. I believe that because arr1 and arr2 will sometimes not be the same lengths then it causes more complication.

James Mak
  • 120
  • 1
  • 14
  • This might help - just merge the two items and then go through and deduplicate: https://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript-and-de-duplicate-items – BobtheMagicMoose Jul 16 '18 at 17:38
  • 2
    Where is `plazaID` coming from? – Mark Jul 16 '18 at 17:40
  • And why do some items have `plazaId` and some don't? Filtering goals are a bit confusing – charlietfl Jul 16 '18 at 17:41
  • Oh sorry I was suppose to change that to parent and child to make it easier to read haha. Let me fix it. – James Mak Jul 16 '18 at 17:41
  • Sorry for the confusion guys. I forgot to edit all of my code to make it generic as possible. – James Mak Jul 16 '18 at 17:46
  • because only objects that have parent and child properties should go into results. The ones without a child property should go into a separate array. – James Mak Jul 16 '18 at 17:50

1 Answers1

2

You could use a hashtable with composed keys to find duplicates:

const hash = {}, result = [], randos = [];

for(const {parent, child, ...data} of arr1.concat(arr2)) {
   if(child) {
     const key = parent + "." + child;
     if(hash[key]) {
       Object.assign(hash[key], data);
     } else {
       result.push(hash[key] = {parent, child, ...data});
     }
   } else {
      randos.push({parent, ...data});
   }
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151