Как уникализировать массив объектов по значениям нескольких свойств?

Есть массив:

const arr = [
  { model: '001', param1: 'a1', param2: 'a2', paramN: 'aN' },
  { model: '001', param1: 'b1', param2: 'a2', paramN: 'bN' },
  { model: '001', param1: 'a1', param2: 'a2', paramN: 'cN' },
  { model: '002', param1: 'c1', param2: 'b2', paramN: 'dN' }
];

Нужно получить новый массив, в который войдут те элементы старого, значения определенных ключей которых - уникальны. Т.е. отсеиваться должны не полностью одинаковые объекты, а только те, в которых значения определенных ключей одинаковы. Например, в приведенном примере объект с индексом 2 не должен попасть в итоговый массив, поскольку первые три его ключа имеют те же значения, что и аналогичные в нулевом объекте. А элемент с индексом 1 - попадает в итоговый массив, потому что его param1 имеет отличающееся значение. Ну и с индексом 3 - тем более попадает.
  • Вопрос задан
  • 246 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Вот вариант максимально короткий и лёгкий для понимания:

const unique = (arr, keys) =>
  arr.filter(n => n === arr.find(m => keys.every(k => m[k] === n[k])));


const result = unique(arr, [ 'model', 'param1', 'param2' ]);

Для вашего случая подходит, но вообще, есть ряд проблем:
  • Иногда косячит

    Если объект присутствует в массиве несколько раз, то такие дубликаты не будут отброшены. Конкретно эта имеет тривиальное решение - вместо ссылок можно сравнивать индексы, под которыми объекты представлены в массиве:

    - arr.filter(n => n === arr.find
    + arr.filter((n, i, a) => i === a.findIndex
  • Недостаточно гибко

    Что если уникализировать надо не по собственно свойствам, а по каким-то производным от них значениям? Например, у объектов есть вложенные объекты, и нужны их свойства; или есть число, а нужен остаток от его деления на какое-то другое число; или есть дата, в которой важен только месяц.
  • Сложность

    Фильтрация линейна, поиск тоже, одно внутри другого даёт квадрат.

Так что вот вариант потяжелее:

const unique = function(arr, keys = n => n) {
  const picked = new Map;
  return arr.filter((...args) => {
    const p = []
      .concat(keys(...args))
      .reduce((acc, k) => acc.set(k, acc.get(k) || new Map).get(k), picked);

    return !p.set(this, p.has(this)).get(this);
  });
}.bind(Symbol());


const result = unique(arr, n => [ n.model, n.param1, n.param2 ]);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
NeiroNx
@NeiroNx
Программист
const arr = [
  { model: '001', param1: 'a1', param2: 'a2', paramN: 'aN' },
  { model: '001', param1: 'b1', param2: 'a2', paramN: 'bN' },
  { model: '001', param1: 'a1', param2: 'a2', paramN: 'cN' },
  { model: '002', param1: 'c1', param2: 'b2', paramN: 'dN' }
];
var param1=[],param2=[];
var _arr=arr.filter(function(e){return !param1.includes(e.param1)&&!param2.includes(e.param2)&&param1.push(e.param1)&&param2.push(e.param2)});
[
{model: "001", param1: "a1", param2: "a2", paramN: "aN"},
{model: "002", param1: "c1", param2: "b2", paramN: "dN"}
]
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
21 нояб. 2024, в 22:21
3000 руб./в час
21 нояб. 2024, в 21:42
100000 руб./за проект
21 нояб. 2024, в 21:30
500 руб./за проект