1

I've been stuck on this problem for a few days now.

let data1 = [{
    project_code: "110",
    project_text: "SampleProject1",
    location: "Seattle",
    startingCost: 0,
    actualCost: 399.99
},
{
    project: "110",
    project_text: "SampleProject1",
    location: "Bellevue",
    startingCost: 0,
    actualCost: 599.99
}];



let data2 = [{
        project: "110",
        project_text: "SampleProject1",
        location: "Seattle",
        startingCost: 249.99,
        actualCost: ""
    },
    {
        project: "110",
        project_text: "SampleProject1",
        location: "Bellevue",
        startingCost: 699.99,
        actualCost: ""
    },
    {
        project: "110",
        project_text: "SampleProject1",
        location: "North Gate",
        startingCost: 899.99,
        actualCost: 1199.99
    }]

The end goal here is that i want it to be merged into one array and the values should be updated like this:

let output = [{
    project: "110",
    project_text: "SampleProject1",
    location: "Seattle",
    startingCost: 249.99, // FROM DATA2
    actualCost: 399.99 // FROM DATA1
},
{
    project: "110",
    project_text: "SampleProject1",
    location: "Bellevue",
    startingCost: 699.99, // FROM DATA2
    actualCost: 599.99 // FROM DATA1
},
{
    // THIS ONE IS ADDING IN NEW DATA
    project: "110",
    project_text: "SampleProject1",
    location: "North Gate",
    startingCost: 899.99,
    actualCost: 1199.99
},

]

I would much prefer a vanilla JS approach but i'll be ok with Lodash as long as i get the output closer to that.

4
  • 1
    Answer here: stackoverflow.com/a/68770314/14032355
    – ikhvjs
    Commented Aug 15, 2021 at 11:22
  • 2
    What property makes the objects in the arrays unqiue? Is it the project_text, or the location property, or both of them, or some other property? To check if there is a duplicate in the other array, you have to be able to determine if there actually is a duplicate.
    – fabian
    Commented Aug 15, 2021 at 11:44
  • @capatain - what are the object key fields? it is not clear.
    – balderman
    Commented Aug 15, 2021 at 11:48
  • There is a reduce function in my code that will take these merged arrays and make the project (not text) as the parent object then the rest becomes the child object in a way. The problem i had is whenever i tried to merge these two, it would end up duplicating itself or never updating that startCost object Commented Aug 15, 2021 at 12:23

3 Answers 3

2

let data1 = [{project_code: "110",project_text: "SampleProject1",location: "Seattle",startingCost: 0,actualCost: 399.99},{project: "110",project_text: "SampleProject1",location: "Bellevue",startingCost: 0,actualCost: 599.99}];
let data2 = [{project: "110",project_text: "SampleProject1",location: "Seattle",startingCost: 249.99,actualCost: ""},{project: "110",project_text: "SampleProject1",location: "Bellevue",startingCost: 699.99,actualCost: ""},{project: "110",project_text: "SampleProject1",location: "North Gate",startingCost: 899.99,actualCost: 1199.99}]
data2.forEach((obj) => {
    let ob = data1.find((e) => e.location == obj.location);
    // YOU CAN ADD OTHER CONDTIONS HERE WITH && OPERATOR
    if (ob !== undefined) {
        obj.actualCost = ob.actualCost;
    }
});
console.log(data2);

The above code will override data2.

let data1 = [{project_code: "110",project_text: "SampleProject1",location: "Seattle",startingCost: 0,actualCost: 399.99},{project: "110",project_text: "SampleProject1",location: "Bellevue",startingCost: 0,actualCost: 599.99}];
let data2 = [{project: "110",project_text: "SampleProject1",location: "Seattle",startingCost: 249.99,actualCost: ""},{project: "110",project_text: "SampleProject1",location: "Bellevue",startingCost: 699.99,actualCost: ""},{project: "110",project_text: "SampleProject1",location: "North Gate",startingCost: 899.99,actualCost: 1199.99}]
var final_result = [];
data2.forEach(({...obj}) => {
    let ob = {...data1.find((e) => e.location == obj.location)};
    //{...data}; used to Clone Object without reference to do not override data1
    if (Object.keys(ob).length !== 0) {
        ob.startingCost = obj.startingCost;
        final_result.push(ob);
    } else {
        final_result.push(obj);
    }
});
console.log(final_result);

  1. {...obj} in the forleach (forEach(({...obj})) used to restrict modifying data2 object when modifying final_result
2
  • 1
    You didn't keep copy of data2, you only copied reference to the original array, so data2 is overrided. If you want to preserve data2 you need to use final_result = [...data2] Commented Aug 15, 2021 at 12:39
  • @NikolaPavicevic, I just noticed it change the reference of list but not for objects inside the list Commented Aug 15, 2021 at 13:38
0

This is how I would do it. Like the comments suggested, which property is suppose to be unique? It would be the criteria I would use to find the data in the other array, I used location because that is the only thing that seemed to be different. You can of course use more than one property to find a match like: item.project === obj.project && item.location === obj.location

data2.forEach(obj=>{
        let object1 = data1.find(item=>item.location === obj.location);
        if(object1){
            object1.startingCost = object1.startingCost || obj.startingCost;
            object1.actualCost = object1.actualCost || obj.actualCost;
        }
        else{
            data1.push(obj);
        }

})

This would default to keeping the data from data1 array if both arrays have data for an object. So change it around for what your program needs are.

0

Try using Array.reduce.

Logic

  • Loop through data2 with Array.reduce.
  • Check the matching node in data1 from data2.
  • If matching node found, merge the startingCost and actualCost.
  • Even though this covers the requirement, dont stop here. You have to verify each nodes in data1 has already been covered in result. If that is not covered, push the missing node to result.
    const data1 = [{
      project: "110",
      project_text: "SampleProject1",
      location: "Seattle",
      startingCost: 0,
      actualCost: 399.99
    },
    {
      project: "110",
      project_text: "SampleProject1",
      location: "Bellevue",
      startingCost: 0,
      actualCost: 599.99
    }];
    
    const data2 = [{
      project: "110",
      project_text: "SampleProject1",
      location: "Seattle",
      startingCost: 249.99,
      actualCost: ""
    },
    {
      project: "110",
      project_text: "SampleProject1",
      location: "Bellevue",
      startingCost: 699.99,
      actualCost: ""
    },
    {
      project: "110",
      project_text: "SampleProject1",
      location: "North Gate",
      startingCost: 899.99,
      actualCost: 1199.99
    }];
    
    const result = data2.reduce((acc, curr) => {
      const matchingNode = data1.find((node) =>
        node.project === curr.project &&
        node.project_text === curr.project_text &&
        node.location === curr.location);
      if(matchingNode) {
        const updatedNode = { ...matchingNode }; // Take a copy of matching node
        updatedNode.startingCost = matchingNode.startingCost || curr.startingCost;
        updatedNode.actualCost = matchingNode.actualCost || curr.actualCost;
        acc.push(updatedNode);
      } else {
        acc.push(curr);
      }
      return acc;
    }, []);
    
    // Since we have looped through data2 to generate the array,
    // we have to ensure that we have not missed any node from data1 aswell
    data1.forEach((node) => {
      const matchingNode = result.find((resultNode) =>
        node.project === resultNode.project &&
        node.project_text === resultNode.project_text &&
        node.location === resultNode.location);
      if (!matchingNode) {
        result.push(node);
      }
    })
    
    console.log(result);

Not the answer you're looking for? Browse other questions tagged or ask your own question.