Как сравнить два массива и вернуть разницу? (Работает в обе стороны?) - PullRequest
2 голосов
/ 20 марта 2019

Так что я хочу добиться этого в ванили, ES6 JS. Пожалуйста, не JQuery! (Лодаш приемлем!)

Обычно у меня есть 2 массива: 1 содержит объекты и 1 содержит идентификаторы.

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
];

const newIds = [1, 2, 3];

Мое текущее решение этой проблемы показано ниже;

const difference = newIds.filter(n => !old.some(o => o.id === n));

В результате возвращается [3].

В основном я сейчас использую это, чтобы определить, что-то отсутствует, и создать его в моей базе данных, если оно отсутствует.

Однако мне нужно сделать обратное. Если что-то удалено, мне нужно сравнить и удалить элемент.

Проблема в этом; Это текущее решение работает только «в одну сторону», поэтому я не могу сделать то, что я сказал выше.

В идеале мне нужно только одно утверждение, будь то создание или удаление, и я хочу, чтобы оно только возвращало идентификаторы вещей, отсутствующих в любом массиве.

Надеюсь, это имеет смысл.

Ответы [ 7 ]

1 голос
/ 20 марта 2019

Чтобы найти значения, которые появляются в одном, но не в другом, используйте lodash's

_.xor(array1, array2);

В вашем случае:

> const _ = require('lodash');

> const old = [
...   { id: 1, name: 'object_1' },
...   { id: 2, name: 'object_2' },
...   { id: 3, name: 'object_3' },
...   { id: 4, name: 'object_4' },
... ];

> const newIds = [1, 3, 5, 7];

> _.xor(old.map(x => x.id), newIds)
[ 2, 4, 5, 7 ]
0 голосов
/ 20 марта 2019

Следующий код найдет разницу с помощью lodash:

const difference = _.difference(newIds, _.map(old, 'id'));
0 голосов
/ 20 марта 2019

Мы можем сделать то же самое в vanilla es6, используя Array#filter и Array#includes.

Здесь я сопоставил старый массив только смассив идентификаторов с помощью Array#map, а затем с помощью фильтра и включает в себя оба массива, я обнаружил симметричную разницу между ними.

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
];
const newIds = [2, 3];
const oldIds =  old.map(({id}) => id);

console.log(getDifference(oldIds, newIds));

function getDifference(oldIds, newIds){
  const diff = [...oldIds.filter(id => !newIds.includes(id)), ...newIds.filter(id => !oldIds.includes(id))];
  return diff;
}

Мы можем сделать это другим способом, используя Array#reduce и Array#findIndex.Просто уменьшите оба массива и верните элементы, которые не повторяются более одного раза, и мы получим симметричную разницу двух массивов.

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
];
const newIds = [2, 3];
const oldIds =  old.map(({id}) => id);

console.log(getDifference(oldIds, newIds));

function getDifference(oldIds, newIds){
  return [...oldIds, ...newIds].reduce((acc, ele) => {
  if(!acc.includes(ele)){
     acc.push(ele);
  }else{
    acc.splice(acc.findIndex(e=> ele === e), 1);
  }
  return acc;
  },[]);
}
0 голосов
/ 20 марта 2019

Вы можете использовать _.get со значением по умолчанию в качестве итерируемого для _.differenceBy, чтобы либо массив объектов, либо массив чисел мог находиться с левой стороны.

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
];

const newIds = [1, 2, 3];

const diff = (a,b) => _.differenceBy(a, b, v => _.get(v, 'id', v))
console.log({ remove: diff(old, newIds), add: diff(newIds, old) })

const otherNewIds = [1];
console.log({ remove: diff(old, otherNewIds), add: diff(otherNewIds, old) })
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
0 голосов
/ 20 марта 2019

Вот решение с использованием ES6:

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
  {
    id: 4,
    name: 'object_2',
  },
];

const newIds = [1, 2, 3];
const oldIds = old.map(o => o.id)

const difference = [...newIds.filter(id => oldIds.indexOf(id) === -1), ...oldIds.filter(id => newIds.indexOf(id) === -1)]

console.log(difference)
0 голосов
/ 20 марта 2019

Надеюсь, это поможет.Я знаю, что это не совсем то, что вы хотите, но это может быть один обходной путь.

const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
  {
    id: 4,
    name: 'object_2',
  },
];

const newIds = [1, 2, 3];

var x1 = old.filter(x => !newIds.includes(x.id)).map(z => z.id)
             .concat(newIds.filter(x => !old.some(y => y.id === x)));
console.log(x1);
0 голосов
/ 20 марта 2019

Вы можете использовать функцию xor из lodash, чтобы получить это.До этого вы можете собрать все идентификаторы из массива old и использовать этот массив идентификаторов для xor.

Проверьте это.

const { xor } = _;
const old = [
  {
    id: 1,
    name: 'object_1',
  },
  {
    id: 2,
    name: 'object_2',
  },
  {
    id: 4,
    name: 'object_4',
  },
];

const newIds = [1, 2, 3];
const oldIds = old.map(o => o.id)
const diff = xor(newIds, oldIds);
console.log(diff)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
...