Есть ли другой способ решить эту проблему forEach, используя карту, фильтр, уменьшить ...? - PullRequest
0 голосов
/ 04 ноября 2018

Если у меня есть два массива таких объектов, как эти два

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];

const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];

На выходе должен быть новый массив, представляющий y но с некоторыми модификациями, если элемент в y имеет id, совпадающий с элементом в x, значение a должно совпадать с x, поэтому на выходе должно быть

[{id: 4, a: 0}, {id: 2, a: 10}, {id: 3, a: 12}]

Это мое решение

const z = [...y];
z.forEach(el => x.map(ele =>  el.a = el.id === ele.id ? ele.a : el.a));

Это простая реализация того, что я делаю в проекте, я беспокоюсь о производительности и вижу, что шаг клонирования массива z = [...y] может быть дорогим, поэтому я ищу решение с использованием функций, которые возвращают новый массив map, filter, reduce ...,

Я пробовал вложенные map и filter, find ... но я закончил со сложными решениями, так есть ли другие решения, которые были бы более производительными и простыми в то же время?

Ответы [ 4 ]

0 голосов
/ 04 ноября 2018

Вместо итерации по x для каждого значения y вы можете создать xObj из x за одну итерацию и в цикле по y просто проверьте, существует ли он в xObj (constant lookup O(1) ), если да затем обновите его, в противном случае используйте существующее значение.

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];

const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];

var xObj = {};

x.forEach(function(val){
  xObj[val.id] = val.a;
});

const newY = y.reduce(function(o,i){
    if(xObj.hasOwnProperty(i.id)){
     i.a = xObj[i.id];
  }
  o.push(i);
  return o;
},[]);

console.log(newY);
0 голосов
/ 04 ноября 2018

Для такой проблемы вы должны заботиться о меньше о вычислительных затратах на создание нового массива, а о больше о расходах Big O, проходящих через несколько массивов несколько раз , И ваше решение, и другое, опубликованное @NitishNarang, выглядят как O (n ^ 2), потому что по мере увеличения ваших массивов количество шагов, необходимых для решения, увеличивается в геометрической прогрессии.

Лично я просто создал бы новый Map() и прошел бы по каждому элементу один за другим, добавив его к Map(), только если значение a, соответствующее этому идентификатору, больше, чем сохраненное в данный момент. По сути, это немного более сложное упражнение по сортировке, за исключением добавления уникальных значений идентификаторов.

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
const myMap = new Map();
for (const ea of x) {
  if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
    myMap.set(ea.id, ea);
  }
}
for (const ea of y) {
  if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
    myMap.set(ea.id, ea);
  }
}
const result = [...myMap.values()];

Это решение O (n), т. Е. Оно линейное. Это означает, что если вы добавите в массив 10, 100 или 1000 элементов x, y или и то, и другое, это только добавит еще много шагов к выполнению. решение вместо 10 ^ 2 или 100 ^ 2 или 1000 ^ 2, потому что вы должны проверять каждый отдельный элемент в каждом массиве на предмет соответствия каждому другому элементу в другом массиве (как вы делаете с вашим исходным решением.)

Редактировать: как указывало @SZenC, приведенное выше решение не совсем корректно, поскольку оно объединяет оба массива. Чтобы выборочно сопоставлять элементы только в том случае, если они изначально существуют в массиве y, просто сначала выполните итерацию по y, а затем заменяйте значения только при выполнении итерации по x, если они уже присутствуют на карте:

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];
const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];
const myMap = new Map();
for (const ea of y) {
  if (!myMap.has(ea.id) || ea.a >= myMap.get(ea.id).a) {
    myMap.set(ea.id, ea);
  }
}
for (const ea of x) {
  if (myMap.has(ea.id) && ea.a >= myMap.get(ea.id).a) {
    myMap.set(ea.id, ea);
  }
}
const result = [...myMap.values()];
0 голосов
/ 04 ноября 2018

Используйте Set для хранения ids, доступного в массиве x, и используйте map over y массив, чтобы проверить, существует ли y's id в Set или нет.

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];

const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];

const mapped = Object.values(x).reduce((acc, {id}) => {
  acc.add(id)
  return acc;
}, new Set());

const result = y.map((obj, index) => mapped.has(obj.id) ? {...obj, a: x[index].a} : obj);

console.log(result);

Надеюсь, это поможет!

0 голосов
/ 04 ноября 2018

Пожалуйста, попробуйте это. Он использует " map " и " find "

const x = [{id: 1, a: 5}, {id: 2, a:10}, {id: 3, a: 12}];

const y = [{id: 4, a: 0}, {id: 2, a: 0}, {id: 3, a: 0}];

const result = y.map(yData => (xResult = x.find(xData => xData.id == yData.id), xResult && { ...yData, a: xResult.a } || yData))

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