сравните и отфильтруйте 2 массива

#javascript #angular #typescript #ecmascript-6

Вопрос:

У меня есть 2 массива. Мне нужно показывать только данные, которые не совпадают со вторым массивом.

 array1 = [
  {
    country: "usa", 
    child: [
      { id: 1, name: "fvsdfsd"   },
      { id: 2, name: "hhghhhfhj" },
    ],
  },
  {
    country: "CA", 
    child: [
      { id: 3, name: "adsada"    },
      { id: 4, name: "hhghhhfhj" },
    ],
  },
  {
    country: "AU",
    child: [
      { id: 5, name: "seven"     },
      { id: 6, name: "hhghhhfhj" },
    ],
  },
];

array2 = [
  { id: 1, name: "fvsdfsd"   },
  { id: 2, name: "hhghhhfhj" },
];
 

Результат:

 [
  {
    country: "usa", 
    child: [],
  },
  {
    country: "CA", 
    child: [
     { id: 3, name: "adsada"    },
     { id: 4, name: "hhghhhfhj" },
    ],
  },
  {
    country: "AU",
    child: [
      { id:5, name: "seven"     },
      { id:6, name: "hhghhhfhj" },
    ],
  },
]
 

Я пытаюсь так, но это не работает

 array1.filter(data => !array2.includes(data.child));
 

Комментарии:

1. К вашему сведению, ваши массивы не являются допустимыми массивами javascript.

Ответ №1:

Ваш код не работает из-за того, как Ecma/Javascript выполняет тестирование на равенство. Array.includes() использует тот же алгоритм Valuezero для определения того, являются ли две вещи «равными».

[И равенство в Javascript является странным]

Сравнение объектов выполняется по ссылке, поэтому два объекта равны, если (и только если) они являются одним и тем же объектом в памяти. Например

 const areEqual = {a:1,b:2} === {a:1,b:2}
 

есть false , как есть

 const areEqual = {a:1,b:2} == {a:1,b:2}
 

Вам нужно провести глубокую проверку на равенство с помощью чего-то вроде lodash isEqual() :

 const _ = require('lodash');
const areEqual = _.isEqual( {a:1,b:2} , {a:1,b:2} ) ; // returns true
 

Так что вы должны быть в состоянии сказать что-то вроде:

 const _ = require('lodash');
const filtered = array1.map( o => {
  return {
    ...o,
    child: _.isEqual( o.child, array2 ) ? [] : o.child ),
  }
});
 

Ответ №2:

Вы не можете сравнивать два разных объекта, используя includes в javascript, потому что includes использует ===. Только ссылки на один и тот же объект будут возвращать значение true с помощью ===. Вам нужно будет написать пользовательскую функцию, которая просматривает все ключи вашего объекта и сравнивает их значения между вашими двумя массивами.

В этой статье объясняются некоторые методы сравнения двух объектов: https://dmitripavlutin.com/how-to-compare-objects-in-javascript/

Ответ №3:

Да, ты можешь попробовать вот так.

array1.map(item1 => ({ ...item1, child: item1.child.filter(childItem => !array2.find(item2 => JSON.stringify(item2) === JSON.stringify(childItem))) }));

Если ключи объекта расположены не в том порядке, как сказал Эверетт Гловьер, вы можете попробовать вот так.

array1.map(item1 => ({ ...item1, child: item1.child.filter(childItem => !array2.find(item2 => item2.id === childItem.id amp;amp; item2.name === childItem.name)) }));

Комментарии:

1. просто предупреждаю: ключи js не всегда находятся в одном и том же порядке, поэтому это может вернуть значение false.

2. Нет никакой гарантии, что два, казалось бы, идентичных (но разных) объекта javascript будут сериализованы в JSON со свойствами в одном и том же порядке. Из статьи MDN по JSON.stringify() теме : » Примечание: Свойства объектов, не являющихся массивами, не гарантируется, что они будут строиться в каком-либо определенном порядке. Не полагайтесь на упорядочение свойств внутри одного и того же объекта при построении».