Удаление дублей из массива в JavaScript
Дубли в массиве появляются часто: из формы, ответа сервера, объединения нескольких списков или после обработки данных. Если повторяющиеся значения не нужны, их можно удалить и оставить только уникальные элементы.
Самый короткий способ для простых значений - использовать Set.
Удаление дублей через Set
Set хранит только уникальные значения. Если передать в него массив, повторяющиеся элементы будут удалены.
let numbers = [1, 2, 2, 3, 4, 4, 5]
let uniqueNumbers = new Set(numbers)
console.log(uniqueNumbers) // Set(5) {1, 2, 3, 4, 5}
В результате получается не массив, а коллекция Set. Если нужен обычный массив, можно использовать Array.from().
let numbers = [1, 2, 2, 3, 4, 4, 5]
let uniqueNumbers = Array.from(new Set(numbers))
console.log(uniqueNumbers) // [1, 2, 3, 4, 5]
То же самое часто записывают через spread-оператор.
let numbers = [1, 2, 2, 3, 4, 4, 5]
let uniqueNumbers = [...new Set(numbers)]
console.log(uniqueNumbers) // [1, 2, 3, 4, 5]
Оба варианта делают одно и то же. Можно выбрать тот, который лучше читается в вашем коде.
Порядок элементов
Set сохраняет порядок первого появления элемента в массиве. Поэтому после удаления дублей значения останутся в привычном порядке.
let tags = ['js', 'html', 'css', 'js', 'html']
let uniqueTags = [...new Set(tags)]
console.log(uniqueTags) // ['js', 'html', 'css']
Повторные ‘js’ и ‘html’ удалились, но первый порядок элементов сохранился.
Удаление дублей через filter()
Удалить дубли можно и без Set, используя метод filter(). Для этого нужно оставить только первое вхождение каждого элемента.
let numbers = [1, 2, 2, 3, 4, 4, 5]
let uniqueNumbers = numbers.filter((number, index, array) => {
return array.indexOf(number) === index
})
console.log(uniqueNumbers) // [1, 2, 3, 4, 5]
Метод indexOf() возвращает индекс первого найденного элемента. Если текущий индекс совпадает с первым найденным, значит элемент встречается впервые.
Такой вариант полезен для понимания логики, но в обычных задачах запись через Set короче и читается проще.
Массив объектов
С объектами Set работает иначе, чем со строками и числами. Два объекта с одинаковыми свойствами все равно считаются разными, если это разные объекты в памяти.
let users = [
{ id: 1, name: 'Alex' },
{ id: 1, name: 'Alex' },
]
let uniqueUsers = [...new Set(users)]
console.log(uniqueUsers.length) // 2
Если нужно удалить дубли из массива объектов, обычно выбирают поле, по которому определяется уникальность. Например, id.
let users = [
{ id: 1, name: 'Alex' },
{ id: 2, name: 'Maria' },
{ id: 1, name: 'Alex' },
]
let uniqueUsers = users.filter((user, index, array) => {
return array.findIndex(item => item.id === user.id) === index
})
console.log(uniqueUsers)
// [{ id: 1, name: 'Alex' }, { id: 2, name: 'Maria' }]
Здесь findIndex() ищет первое появление пользователя с таким же id. Если текущий элемент и есть первое появление, он остается в массиве.
Когда какой способ использовать
Если массив состоит из строк, чисел, булевых значений или других простых значений, чаще всего достаточно Set.
let roles = ['admin', 'user', 'admin']
let uniqueRoles = [...new Set(roles)]
Если массив состоит из объектов, нужно сначала решить, по какому полю объекты считаются одинаковыми: id, email, slug или другому значению.
Итого
Для удаления дублей из массива простых значений удобнее всего использовать Set и преобразовать результат обратно в массив. Для массива объектов нужно явно указать правило уникальности, потому что одинаковые по содержимому объекты для JavaScript остаются разными объектами.