Сделаем функцию, которая будет принимать следующие параметры:
- массив, подлежащий уникализации
- функцию, принимающую элемент массива и возвращающую значение, по которому осуществляется уникализация
Чтобы можно было делать так:
const result = unique(arr, n => n.user.id);
.
Какие тут возможны варианты:
const unique = (arr, key) =>
Object.values(Object.fromEntries(arr.map(n => [ key(n), n ])));
// или, если в результирующий массив должны попадать те из "одинаковых" элементов,
// что расположены в исходном массиве первыми
const unique = (arr, key) =>
Object.values(arr.reduce((acc, n) => (acc[key(n)] ??= n, acc), {}));
// или, если надо также сохранять взаимное расположение элементов
const unique = (arr, key) =>
arr.filter(function(n) {
const k = key(n);
return !(this[k] = this.hasOwnProperty(k));
}, {});
Если значения, по которым осуществляется уникализация, могут, будучи различными, иметь одинаковый строковый эквивалент, то на помощь приходят
Map
и
Set
:
const unique = (arr, key) =>
Array.from(new Map(arr.map(n => [ key(n), n ])), n => n[1]);
// или (в отличие от объекта, Map запоминает порядок вставки,
// так что тут взаимное расположение элементов сохраняется)
const unique = (arr, key) =>
[...arr.reduce((acc, n) => {
const k = key(n);
return acc.set(k, acc.get(k) ?? n);
}, new Map).values()];
// или
const unique = (arr, key) =>
arr.filter(function(n) {
const k = key(n);
return !this.has(k) && this.add(k);
}, new Set);