比较 2 个具有不同形状的对象数组并根据特定 属性 删除重复项

Compare 2 Arrays of objects with different shapes and remove duplicates based on specific property

我在 JavaScript 中有 2 个对象数组。两个数组在其对象中都包含一个名为 car_id 的类似 属性。 如何删除数组 1 中具有与数组 2 中的对象相似的汽车 ID 值的对象。 在下面的示例中,我应该得到 {car_id: 3, make: "Chevy", model: "Tahoe", year: 2003} 作为最终值。

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"},
];

您可以创建一个包含来自 cars2 的所有 ID 的过滤数组,并使用它来过滤 cars1 中的项目,如下所示:

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)

实际上 OP 寻找 difference of two sets

与数组一样,可以基于 reduce, and for the OP's special case does combine it with a nested find 已经可靠的方法来过滤掉不匹配的项目 ...

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; }

开发人员通常不知道第二个 thisArg argument which all Array methods are capable of except of reduce. Thus the above approach, now based on the more intuitiv filter,可以重构为更易读的解决方案...

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; }

这可能不是最简洁的方法,也不是很通用,但它适用于您的示例和 returns 您想要的项目。我保留了与您示例中相同的变量名称,因此您可以继续尝试。

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])
}

我遍历第一个数组并尝试在第二个数组中找到 car_id。如果它不存在,isIn2ndArr 将具有未定义的值,这是假的。因此,我们现在可以只使用 if NOT 语句将项目推送到新数组。

注意一点,提醒一下:由于item本身就是对象,JS会在内存中保留对原始对象的引用。因此,如果您更改新数组中的 keys/properties 个对象,它也会影响原始 cars1 数组中的对象。 JS 可能会像那样奇怪 ;) 这个问题有几种变通方法,但这不是你的问题。