-1

I have 2 arrays of objects in JavaScript. Both Arrays contain a similar property called car_id in their objects. How can I remove the objects in array 1 with a similar car id value as objects in array 2. In the example below, I should get {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003} as the final value.

var cars1 = [
    {car_id: 1, make: "Honda", model: "Civic", year: 2001, driver: "John"},
    {car_id: 2, make: "Ford",  model: "F150",  year: 2002, driver: "Max"},
    {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003, driver: "Jane"},
];

var cars2 = [
    {car_id: 1, make: "Honda",    color: "red",  engine_no: "AB567"},
    {car_id: 2, make: "Ford",    color: "blue",  engine_no: "AB568"},
    {car_id: 6, make: "Toyota",    color: "green",  engine_no: "AB569"},
];
  • I don't actually see a question here. – Beska Aug 05 '21 at 12:41
  • @JulienSorin I think the OP request does not mention any merging; the request is just to filter some items out of `cars1` not to merge the two arrays end remove the duplicates – secan Aug 05 '21 at 12:43
  • Does this answer your question? [Filter array of objects based on another array in javascript](https://stackoverflow.com/questions/46894352/filter-array-of-objects-based-on-another-array-in-javascript) – secan Aug 05 '21 at 12:49
  • @SamuelBassey ... are there any questions left regarding all the provided approaches? – Peter Seliger Aug 05 '21 at 17:36
  • Does this answer your question? [Merge two array of objects based on a key](https://stackoverflow.com/questions/46849286/merge-two-array-of-objects-based-on-a-key) – Kelvin Schoofs Aug 05 '21 at 18:35

3 Answers3

1

You could create a filtering array containing all IDs from cars2 and use it to filter items in cars1 as follow:

const cars1 = [
  {car_id: 1, make: "Honda", model: "Civic", year: 2001, driver: "John"},
  {car_id: 2, make: "Ford",  model: "F150",  year: 2002, driver: "Max"},
  {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003, driver: "Jane"},
];

const cars2 = [
  {car_id: 1, make: "Honda",    color: "red",  engine_no: "AB567"},
  {car_id: 2, make: "Ford",    color: "blue",  engine_no: "AB568"},
  {car_id: 6, make: "Toyota",    color: "green",  engine_no: "AB569"},
];

const idFilter = cars2.map(item => item.car_id);

const filteredArray = cars1.filter(item => !idFilter.includes(item.car_id));

// test
console.log(filteredArray)
secan
  • 2,622
  • 1
  • 7
  • 24
0

Actually the OP looks for the difference of two sets.

As so often with arrays, one can base an already reliable approach on reduce, and for the OP's special case does combine it with a nested find, in order to filter out the the non matching item(s) ...

const cars1 = [
  {car_id: 1, make: "Honda", model: "Civic", year: 2001, driver: "John"},
  {car_id: 2, make: "Ford",  model: "F150",  year: 2002, driver: "Max"},
  {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003, driver: "Jane"},
];
const cars2 = [
  {car_id: 1, make: "Honda",    color: "red",  engine_no: "AB567"},
  {car_id: 2, make: "Ford",    color: "blue",  engine_no: "AB568"},
  {car_id: 6, make: "Toyota",    color: "green",  engine_no: "AB569"},
];

function collectIncomplementedCarIdItem(collector, item/*, idx, arr*/) {
  const { reference, list } = collector;

  if (!reference.find(refItem =>
    refItem.car_id === item.car_id)
  ) {
    // in case one just wants to filter the car item reference.
    //
    list.push(item);

    // // in case one wants to furtherly process/mutate
    // // the filtered car item but does not want to have
    // // the original car item reference effected.
    // //
    // // create a shallow copy, which for the given
    // // car item structure is already sufficient enough.
    // //
    // list.push(Object.assign({}, item));
  }
  return collector;
}

console.log(
  'cars1.reduce(collectIncomplementedCarIdItem, { reference: cars2, list: [] }).list ...',
  cars1.reduce(collectIncomplementedCarIdItem, { reference: cars2, list: [] }).list
);
console.log(
  'cars2.reduce(collectIncomplementedCarIdItem, { reference: cars1, list: [] }).list ...',
  cars2.reduce(collectIncomplementedCarIdItem, { reference: cars1, list: [] }).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Often developers are unaware of the second thisArg argument which all Array methods are capable of except of reduce. Thus the above approach, now based on the more intuitiv filter, can be refactored to an even better readable solution ...

const cars1 = [
  {car_id: 1, make: "Honda", model: "Civic", year: 2001, driver: "John"},
  {car_id: 2, make: "Ford",  model: "F150",  year: 2002, driver: "Max"},
  {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003, driver: "Jane"},
];
const cars2 = [
  {car_id: 1, make: "Honda",    color: "red",  engine_no: "AB567"},
  {car_id: 2, make: "Ford",    color: "blue",  engine_no: "AB568"},
  {car_id: 6, make: "Toyota",    color: "green",  engine_no: "AB569"},
];

function isIncomplementedCarIdItemOfBoundReference(item/*, idx, arr*/) {
  const reference = this; // bound array / reference.

  return !reference.find(refItem =>
    refItem.car_id === item.car_id
  )
}

console.log(
  'cars1.filter(isIncomplementedCarIdItemOfBoundReference, cars2) ...',
  cars1.filter(isIncomplementedCarIdItemOfBoundReference, cars2)
);
console.log(
  'cars2.filter(isIncomplementedCarIdItemOfBoundReference, cars1) ...',
  cars2.filter(isIncomplementedCarIdItemOfBoundReference, cars1)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • If I may... the code you are proposing is interesting and provides some valuable "food for thought" but in the context of the question asked by the OP it seems to me a bit of an overly complicate way of producing an output that is arbitrarily different from the one expected by the OP. Could you elaborate a little bit more on why you would suggest this approach, please? Please notice my intention is not to offend or belittle you and I apologize if I inadvertently did (English is not my native language); my intention is just to understand your thought process and possibly learn something from it – secan Aug 05 '21 at 13:32
  • 1
    @secan ... It is about writing reusable and readable code. Thus looking always for an approach which makes no assumptions about variables/references outside of such a solution's scope. Which automatically leads to named functions that get all information passed (in)to, will be consumed by, and also use themself, the most obvious methods of build in objects, and whose names read what each of the function actually does or is responsible for. – Peter Seliger Aug 05 '21 at 13:56
  • 1
    @secan ... At least for me from reading something like ... `cars1.filter(isIncomplementedCarIdItemOfBoundReference, cars2)` while looking into the car item's structures and into the implementation of a single function like `isIncomplementedCarIdItemOfBoundReference` ... I immediately get an understanding of what the code in its entirety is about. And I'm confident that other developers experience the same. – Peter Seliger Aug 05 '21 at 14:05
  • 1
    Thank you very much for taking the time to answer me. I get the point on re-usability of code but I have some perplexity about whether it actually is more readable; I'll have to give some further consideration on pros (e.g. the function name is self-descriptive) and cons (e.g. a very long function name can be "harder to process"... for the brain, I mean, not the computer). Anyway I really appreciate your kind answer; thanks again. :) – secan Aug 05 '21 at 14:17
0

This may not be the cleanest approach and it is not very general, but it works for your example and returns the items you want. I kept the same variable names as in your example, so you can just go ahead and try it.

var uniqueCars = [];
for (let i = 0; i < cars1.length; i++) {
    let isIn2ndArr = cars2.find(x => x.car_id === cars1[i].car_id)
    if (!isIn2ndArr) uniqueCars.push(cars1[i])
}

I loop through the 1st array and try to find the car_id in the 2nd array. If it doesn't exist, isIn2ndArr will have the value undefined, which is falsy. Thus, we can now just use an if NOT statement to push the item to a new array.

Careful though, just a reminder: Since the items themselves are objects, JS will keep a reference in memory to the original object. So if you change keys/properties of objects in the new array, it will also affect the object in the original cars1 array. JS can be weird like that ;) There is several work-arounds for this issue, but that wasn't your question.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Foxcode
  • 1,279
  • 11
  • 10