How can I compare objects in 2 arrays in Javascript & return the missing elements?

133 Views Asked by At

Is there a way to compare an incomplete array to the source of truth array & return the missing elements? The array consists of objects & some of the objects have an array of objects.

let incompleteArr =[
          {
            "name": "Extra Toppings (Small)",
            "modifier_options": [{
                    "name": "Corn",
                    "price": 0.75
                },
                {
                    "name": "Extra mozzarella",
                    "price": 0.9
                },
                {
                    "name": "Onion",
                    "price": 0.45
                }
            ]
        },
        {
            "name": "Extra Toppings (Large)",
            "modifier_options": [{
                    "name": "Corn",
                    "price": 1.2
                },
                {
                    "name": "Extra Mozzarella",
                    "price": 1.7
                }
            ]
        }
    ]
  }]

  let completeArr =[
            {
                "name": "Extra Toppings (Small)",
                "modifier_options": [
                    {
                        "name": "Corn",
                        "price": 0.75
                    },
                    {
                        "name": "Extra mozzarella",
                        "price": 1.2
                    },
                    {
                        "name": "Extra Anchovies",
                        "price": 0.7
                    }
                ]
            },
            {
                "name": "Extra Toppings (Large)",
                "modifier_options": [
                    {
                        "name": "Corn",
                        "price": 1.2
                    },
                    {
                        "name": "Extra mozzarella",
                        "price": 1.7
                    }
                ]
            },
            {
                "name": "Extra Burger Toppings (Small)",
                "modifier_options": [
                    {
                        "name": "Extra Onion",
                        "price": 0.5
                    },
                    {
                        "name": "Extra Tomato",
                        "price": 0.55
                    },
                    {
                        "name": "Extra Cheese",
                        "price": 0.65
                    },
                    {
                        "name": "Extra Mayo",
                        "price": 0.3
                    },
                    {
                        "name": "Extra Patty",
                        "price": 2.5
                    }
                ]
            },
            {
                "name": "Extra Burger Toppings (Medium)",
                "modifier_options": [
                    {
                        "name": "Extra Onion",
                        "price": 0.6
                    },
                    {
                        "name": "Extra Tomato",
                        "price": 0.65
                    },
                    {
                        "name": "Extra Cheese",
                        "price": 0.75
                    },
                    {
                        "name": "Extra Mayo",
                        "price": 0.4
                    },
                    {
                        "name": "Extra Patty",
                        "price": 2.9
                    }
                ]
            },
            {
                "name": "Extra Burger Toppings (Large)",
                "modifier_options": [
                    {
                        "name": "Extra Onion",
                        "price": 0.8
                    },
                    {
                        "name": "Extra Tomato",
                        "price": 0.9
                    },
                    {
                        "name": "Extra Cheese",
                        "price": 0.95
                    },
                    {
                        "name": "Extra Mayo",
                        "price": 0.6
                    },
                    {
                        "name": "Extra Patty",
                        "price": 3.5
                    }
                ]
            }
        ]

Desired result is to return an array of missing elements. For example the "name" Extra Toppings (Small) must exist in the incompleteArr & the completeArr. Then the "modifier_options" must also be compared. Any modifier_options not in the incompleteArr must be pushed into the array of missing elements.

I have tried this so far

let missingMod = gfMods.filter(mod => lvMods.every(mod2 => !mod2.name.includes(mod.name)))

The output as expected is the missing items BUT I am not getting the missing nested array items from the modifier_options object. I have an idea that I need to loop through the arrays checking that the "names" exist & then a second loop to check if the modifier_options all exist. This is where I have been stuck.

[{
name:"Extra Burger Toppings (Small)",
modifier_options: [{
name:"Extra Onion",
price:0.5},
{name:"Extra Tomato",
price:0.55},
{name:"Extra Cheese",
price:0.65},
{name:"Extra Mayo",
price:0.3},
{name:"Extra Patty",
price:2.5}
]},
{name:"Extra Burger Toppings (Medium)",
modifier_options: [{
name:"Extra Onion",
price:0.6},
{name:"Extra Tomato",
price:0.65},
{name:"Extra Cheese",
price:0.75},
{name:"Extra Mayo",
price:0.4},
{name:"Extra Patty",
price:2.9}]
},
{name:"Extra Burger Toppings (Large)",
modifier_options: [{
name:"Extra Onion",
price:0.8},
{name:"Extra Tomato",
price:0.9},
{name:"Extra Cheese",
price:0.95},
{name:"Extra Mayo",
price:0.6},
{name:"Extra Patty",
price:3.5}]
}]
1

There are 1 best solutions below

5
Vektor On BEST ANSWER

This solution utilizes the .reduce(), .find(), .some(), and .filter() Array methods.

// Reduces the complete array, to a list of missing values from
// the incomplete array.
const result = completeArr.reduce((prev, next) => {
  // Finds whether the object exists in the incomplete array.
  // _main will hold the matching object from the incomplete
  // array if found, or undefined otherwise.
  const _main = incompleteArr.find(obj => obj.name == next.name);
  
  // If it does find, stop here and check for missing
  // values inside modifier options.
  if(_main){
    // .filter to get the missing modifier objects from the 
    // incomplete array. Done by checking if a
    // modifier option of the complete array 
    // is NOT present in the incomplete array's
    // modifier options list.
    const _mod = next.modifier_options.filter(next_mod => !_main.modifier_options.some(main_mod => next_mod.name == main_mod.name));
    
    // Add _mod(containing missing modifier options) to
    // the accumulating array and return.
    return [...prev, {parent: next.name, modifier_options: _mod}];
  }
  
  // This next object doesn't exist in the incomplete 
  // array as it wasn't found, so add it to the accumulating
  // list of missing items.
  return [...prev, next];
}, []);

let incompleteArr = [
      {
        "name": "Extra Toppings (Small)",
        "modifier_options": [{
                "name": "Corn",
                "price": 0.75
            },
            {
                "name": "Extra mozzarella",
                "price": 0.9
            },
            {
                "name": "Onion",
                "price": 0.45
            }
        ]
    },
    {
        "name": "Extra Toppings (Large)",
        "modifier_options": [{
                "name": "Corn",
                "price": 1.2
            },
            {
                "name": "Extra Mozzarella",
                "price": 1.7
            }
        ]
    }
];

let completeArr = [
    {
        "name": "Extra Toppings (Small)",
        "modifier_options": [
            {
                "name": "Corn",
                "price": 0.75
            },
            {
                "name": "Extra mozzarella",
                "price": 1.2
            },
            {
                "name": "Extra Anchovies",
                "price": 0.7
            }
        ]
    },
    {
        "name": "Extra Toppings (Large)",
        "modifier_options": [
            {
                "name": "Corn",
                "price": 1.2
            },
            {
                "name": "Extra mozzarella",
                "price": 1.7
            }
        ]
    },
    {
        "name": "Extra Burger Toppings (Small)",
        "modifier_options": [
            {
                "name": "Extra Onion",
                "price": 0.5
            },
            {
                "name": "Extra Tomato",
                "price": 0.55
            },
            {
                "name": "Extra Cheese",
                "price": 0.65
            },
            {
                "name": "Extra Mayo",
                "price": 0.3
            },
            {
                "name": "Extra Patty",
                "price": 2.5
            }
        ]
    },
    {
        "name": "Extra Burger Toppings (Medium)",
        "modifier_options": [
            {
                "name": "Extra Onion",
                "price": 0.6
            },
            {
                "name": "Extra Tomato",
                "price": 0.65
            },
            {
                "name": "Extra Cheese",
                "price": 0.75
            },
            {
                "name": "Extra Mayo",
                "price": 0.4
            },
            {
                "name": "Extra Patty",
                "price": 2.9
            }
        ]
    },
    {
        "name": "Extra Burger Toppings (Large)",
        "modifier_options": [
            {
                "name": "Extra Onion",
                "price": 0.8
            },
            {
                "name": "Extra Tomato",
                "price": 0.9
            },
            {
                "name": "Extra Cheese",
                "price": 0.95
            },
            {
                "name": "Extra Mayo",
                "price": 0.6
            },
            {
                "name": "Extra Patty",
                "price": 3.5
            }
        ]
    }
];

const result = completeArr.reduce((prev, next) => {
  const _main = incompleteArr.find(obj => obj.name == next.name);
  if(_main){
    const _mod = next.modifier_options.filter(next_mod => !_main.modifier_options.some(main_mod => next_mod.name == main_mod.name));
    return [...prev, {parent: next.name, modifier_options: _mod}];
  }
  return [...prev, next];
}, []);

console.log(result);

Note: It'll return "Extra mozzarella" from "Extra Toppings (Large)" because of the case difference. Also, forgive the poor variable names, I hope this solution solves your problem.

Update

As per the request of OP, I added the .name of the parent object the missing modifier_options belong to.