Удаление повторяющихся объектов из массива JavaScript
Предположим, что у нас есть массив объектов, пример которого приведен ниже:
const books = [
{
name: "My Sister the Serial Killer",
author: "Oyinkan Braithwaite"
},
{
name: "Educated",
author: "Tara Westover"
},
{
name: "My Sister the Serial Killer",
author: "Oyinkan Braithwaite"
}
];
Первый и последний объект в массиве являются одинаковыми. Как удалить дубликаты из массива? На удивление, в JavaScript решить такую задачу довольно сложно. Чтобы понять это, рассмотрим, как удалить повторения из одномерного массива, элементами которого являются строки.
Удаление дубликатов из одномерных массивов (легкий способ)
Предположим, что у нас есть массив строк:
const strings = [
"My Sister the Serial Killer",
"Educated",
"My Sister the Serial Killer"
];
Чтобы удалить повторяющиеся элементы из такого массива, можно использовать метод filter() вместе с методом indexOf(). Он позволяет проверить, не повторяется ли какой-либо из элементов.
const filteredStrings = strings.filter((item, index) => {
// Возврат к новому массиву, если индекс текущего элемента
//совпадает с другим
return strings.indexOf(item) === index;
});
strings.indexOf(item) всегда будет возвращать индекс первого вхождения элемента, мы можем выяснить, является ли текущий элемент повторяющимся в фильтрующей цикле. Если да, мы не возвращаем его в новый массив, созданный методом filter().
Объекты не работают одинаково
Этот способ не подходит для сравнения объектов. В JavaScript любые два объекта с одинаковыми свойствами и значениями не считаются одинаковыми.
const a = {
name: "My Sister the Serial Killer",
author: "Oyinkan Braithwaite"
};
const b = {
name: "My Sister the Serial Killer
",
author: "Oyinkan Braithwaite"
};
a === b // false
В JavaScript объекты имеют ссылочный тип. Поэтому равными будут только ссылки на один и тот же объект. Таким образом, indexOf(object) в массиве объектов всегда будет возвращать индекс переданного элемента, даже если там есть другой объект с одинаковыми свойствами и значениями.
Мое решение
Единственным способом сравнения объектов является проверка свойств и значений каждого из них. Поэтому решение заключается в ручной проверке. Механизм реализации:
- Проверять каждый элемент в массиве на соответствие последующему, который идет после него.
- Проверять только те элементы, которые не были определены как дубликаты другого элемента.
- Если значения каждого свойства объектов одинаковы, проверить, имеют ли объекты одинаковые ключи.
Финальная функция выглядит так:
function removeDuplicates(arr) {
const result = [];
const duplicatesIndices = [];
// Перебираем каждый элемент в исходном массиве
arr.forEach((current, index) => {
if (duplicatesIndices.includes(index)) return;
result.push(current);
// Сравниваем каждый элемент в массиве после текущего
for (let comparisonIndex = index + 1; comparisonIndex < arr.length; comparisonIndex++) {
const comparison = arr[comparisonIndex];
const currentKeys = Object.keys(current);
const comparisonKeys = Object.keys(comparison);
// Проверяем длину массивов
if (currentKeys.length !== comparisonKeys.length) continue;
// Проверяем значение ключей
const currentKeysString = currentKeys.sort().join("").toLowerCase();
const comparisonKeysString = comparisonKeys.sort().join("").toLowerCase();
if (currentKeysString !== comparisonKeysString) continue;
// Проверяем индексы ключей
let valuesEqual = true;
for (let i = 0; i < currentKeys.length; i++) {
const key = currentKeys[i];
if ( current[key] !== comparison[key] ) {
valuesEqual = false;
break;
}
}
if (valuesEqual) duplicatesIndices.push(comparisonIndex);
} // Конец цикла
});
return result;
}