фильтровать массив объектов другим массивом объектов - PullRequest
0 голосов
/ 04 декабря 2018

Я хочу отфильтровать массив объектов по другому массиву объектов.

У меня есть 2 массива таких объектов:

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];
const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

и я хочу отфильтровать array от anotherArray и вернуть элементы, которые не существуют в anotherArray и имеют sub.

Итак, мой желаемый результат:

[ { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } ]

Примечание: я сделал это с циклом for, но он работает слишком медленно.Я хочу сделать это с помощью метода фильтра массива

Код, который я имею с для цикла:

for (let i = 0; i < array.length; i += 1) {
    let exist = false;
    const item = array[i];
    for (let j = 0; j < anotherArray.length; j += 1) {
      const anotherItem = anotherArray[j];
      if (item.id === anotherItem.id) {
        exist = true;
      }
    }
    if (item.sub && !exist) {
      this.newArray.push({
        text: `${item.sub.name} / ${item.name}`,
        value: item.id,
      });
    }
  }

Ответы [ 4 ]

0 голосов
/ 04 декабря 2018

Вы можете использовать Array.filter, а затем Array.some, так как последний вернет логическое значение вместо элемента, как Array.find:

const a1 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } }, { id: 4, name: 'a4', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; 
const a2 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ];

const result = a1.filter(({id, sub}) => !a2.some(x => x.id == id) && sub)

console.log(result)
0 голосов
/ 04 декабря 2018

Вы можете использовать JSON.stringify для сравнения двух объектов.Было бы лучше написать функцию, которая рекурсивно сравнивает все свойства объектов.

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];
const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const notIn = (array1, array2) => array1.filter(item1 => {
    const item1Str = JSON.stringify(item1);
    return !array2.find(item2 => item1Str === JSON.stringify(item2))
  }
);

console.log(notIn(array, anotherArray));
0 голосов
/ 04 декабря 2018

Хорошо, давайте решим этот шаг за шагом.

Чтобы упростить процесс, давайте предположим, что два элемента можно считать равными, если они оба имеют одинаковые id.

Первый подходчто я бы использовал, чтобы перебрать первый массив и, для каждого элемента, перебрать второй, чтобы проверить условия, которые вы определили выше.

const A = [ /* ... */]
const B = [ /* ... */]

A.filter(el => {
  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB && !!B.sub
})

Если мы уверены, что элементы в A ив B действительно одинаковы, когда они имеют одинаковый идентификатор, мы могли бы пропустить все элементы A без свойства sub, чтобы выполнить его немного

A.filter(el => {
  if (!el.sub) return false

  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB
})

Теперь, если наши массивы больше чемэто означает, что мы тратим много времени на поиск элемента в B. Обычно в этих случаях я преобразую массив, в котором я ищу, в карту, как это

var BMap = {}
B.forEach(el => {
  BMap[el.id] = el
})

A.filter(el => {
  if (!el.sub) return false

  return !!BMap[el.id]
})

В этомто, как вы «тратите» немного времени на создание своей карты в начале, но затем вы можете быстрее находить свои элементы.

Отсюда может быть еще больше оптимизаций, но я думаю, что это конецна этот вопрос

0 голосов
/ 04 декабря 2018

Как упоминал Феликс, Array#filter не будет работать быстрее, чем собственный цикл for, однако, если вы действительно хотите использовать его как функциональный способ, вот одно из возможных решений:

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const r = array.filter((elem) => !anotherArray.find(({ id }) => elem.id === id) && elem.sub);

console.log(r);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...