Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Set vs Array: удаляем дубликаты в тегах без лишних костылей

Set vs Array: удаляем дубликаты в тегах без лишних костылей

Запланировано Прикреплена Закрыта Перенесена JavaScript
setдубликатыпроизводительность
1 Сообщения 1 Постеры 4 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал отредактировано
    #1

    Когда нужно обработать теги поста и оставить только уникальные значения, половина разработчиков тянется к привычным методам массивов, а потом удивляется, почему код работает медленнее, чем хотелось бы. На самом деле задача решается в одну строку, если знать нужный инструмент.

    В этой статье разберёмся, почему Set - это не просто красивое решение, а настоящий выигрыш по производительности. Посмотрим, как он работает под капотом, какие ошибки подстерегают новичков, и когда Array всё же может быть полезнее.

    Чем Set отличается от Array

    Массив - это индексированная коллекция. Значения упорядочиваются по позиции: нулевой элемент, первый, второй. Каждый раз, когда нужно проверить, есть ли уже такой элемент, приходится либо использовать indexOf(), либо перебирать весь массив циклом. Для массива с тысячей тегов это быстро становится боль.

    Set - это совсем другое животное. Это коллекция ключей, где каждое значение хранится только один раз. Когда вы пытаетесь добавить дубликат, Set просто его проигнорирует. Нет никаких проверок перед вставкой - это встроено в саму структуру данных.

    • Индексированность: Array упорядочивает по индексам (0, 1, 2…), Set упорядочивает по ключам
    • Уникальность: Array хранит всё, Set автоматически отбрасывает дубликаты
    • Производительность проверки: Array требует линейного поиска, Set проверяет за O(1)
    • Порядок элементов: Оба сохраняют порядок вставки, но только Array позволяет быстро обратиться по индексу

    Как Set обрабатывает примитивы и объекты

    Вот тут начинается самое интересное. Set работает с примитивами (строки, числа, boolean) по значению, а с объектами по ссылке.

    Если у вас массив тегов вроде ['react', 'vue', 'react', 'angular'] - Set справится за миллисекунду. Преобразовываем в Set и обратно в массив:

    const tags = ['react', 'vue', 'react', 'angular'];
    const uniqueTags = [...new Set(tags)];
    // Результат: ['react', 'vue', 'angular']
    

    Но если вы решили хранить теги как объекты {name: 'react'}, вот тут Set ловит косяк. Даже если два объекта выглядят идентично, это разные ссылки в памяти:

    const tagObjects = [{id: 1}, {id: 1}, {id: 1}];
    const uniqueTagObjects = new Set(tagObjects);
    console.log(uniqueTagObjects.size); // 3, не 1!
    

    Почему так? Потому что Set сравнивает объекты по ссылке, а не по содержимому. Каждый {id: 1} - это разные адреса в памяти. Если вам действительно нужно дедублицировать объекты, придётся писать свою логику или использовать Map с кастомным ключом.

    • Примитивы: Сравниваются по значению - два одинаковых числа считаются дубликатом
    • Объекты: Сравниваются по ссылке - два объекта с одинаковыми свойствами это разные элементы
    • Смешанные типы: 1 (число) и '1' (строка) - разные значения, Set оба сохранит
    • Null и undefined: Сохраняются по одному экземпляру

    Производительность: цифры говорят сами за себя

    Если вы слышали, что Set быстрее - это не маркетинг, это факт. Тесты на реальных объёмах данных показывают: Set быстрее Array с filter в десятки раз, а reduce в сотню раз.

    Когда вы вызываете arr.indexOf() или arr.includes() для проверки наличия элемента, браузер проходит весь массив с начала. Это O(n) операция. Повторяем проверку для каждого элемента - получаем O(n²). Set использует хеш-таблицу внутри и проверяет за O(1). Для массива из тысячи элементов разница измеряется в порядках величины.

    Сравните эти подходы:

    Подход Код Скорость
    Set [...new Set(arr)] Базовая
    Filter + indexOf arr.filter((v, i) => arr.indexOf(v) === i) ~10x медленнее
    Reduce arr.reduce((acc, v) => acc.includes(v) ? acc : [...acc, v], []) ~100x медленнее
    Цикл с проверкой for + arr.includes() ~20x медленнее
    // Измеряем самый быстрый способ
    const testArray = Array.from({length: 10000}, (_, i) => i % 100);
    
    console.time('Set approach');
    const result1 = [...new Set(testArray)];
    console.timeEnd('Set approach'); // ~1ms
    
    console.time('Filter approach');
    const result2 = testArray.filter((v, i) => testArray.indexOf(v) === i);
    console.timeEnd('Filter approach'); // ~50ms
    

    Методы Set для работы с тегами

    Kогда вы знаете, какие методы есть, работать с Set становится проще. Вот что вам нужно для обработки тегов:

    • set.add(value) - добавить тег в множество, дубликаты игнорируются автоматически
    • set.has(value) - проверить, есть ли тег уже в множестве (быстро, за O(1))
    • set.delete(value) - удалить конкретный тег
    • set.clear() - очистить всё множество
    • set.size - узнать количество уникальных тегов

    Практический пример - обработка тегов поста:

    const postTags = new Set();
    
    // Добавляем теги пользователя
    postTags.add('javascript');
    postTags.add('frontend');
    postTags.add('javascript'); // Игнорируется
    
    // Проверяем наличие
    if (postTags.has('javascript')) {
      console.log('Тег уже есть');
    }
    
    // Итерируем в порядке добавления
    postTags.forEach(tag => console.log(tag));
    // javascript, frontend
    
    // Удаляем ненужное
    postTags.delete('frontend');
    console.log(postTags.size); // 1
    

    Итерация всегда происходит в порядке вставки элементов. Это важно - если вы хотите сохранить порядок тегов, как их вводил пользователь, Set не подведёт.

    Когда Array ещё может быть полезен

    Не преувеличивайте, Set - не серебряная пуля. Есть сценарии, где Array всё ещё нужен.

    Если вам нужно частно обращаться по индексу - Array выигрывает. tags это O(1), а из Set элемент по номеру не достать. Также если вы работаете с очень маленькими коллекциями (пара десятков элементов), производительность Set не будет видна, а код может быть понятнее с привычным Array.

    Для древних браузеров (IE10 и ниже) Set просто не существует - придётся fallback’ить на Array. И если вы делаете какой-то специфический обход или трансформацию данных, Array методы могут быть удобнее.

    // Array vs Set: когда Array проще
    const tags = ['react', 'vue', 'angular'];
    
    // Нужна трансформация каждого элемента
    const tagsByLength = tags.map(tag => tag.length);
    // Set это не может делать встроенно
    
    // Нужна фильтрация по условию
    const longTags = tags.filter(tag => tag.length > 5);
    // Set тоже не может
    
    // Нужен доступ по индексу
    const firstTag = tags;
    // Set заставит конвертировать в массив
    

    Практический паттерн: обработка тегов поста

    Большинство задач с дедупликацией тегов решаются одинаково. Вот универсальный подход, который работает в 90% случаев:

    function getUniqueTags(rawTags) {
      // rawTags может быть грязным - с пробелами, дубликатами, пустыми строками
      return [
        ...new Set(
          rawTags
            .map(tag => tag.trim().toLowerCase())
            .filter(tag => tag.length > 0)
        )
      ];
    }
    
    const userInput = ['React', 'REACT', ' vue ', '', 'Angular', 'react'];
    const cleanTags = getUniqueTags(userInput);
    console.log(cleanTags);
    // ['react', 'vue', 'angular']
    

    Всё чётко: сначала нормализуем данные через map и filter, потом Set отрезает дубликаты, потом разворачиваем обратно в массив.

    • Нормализация перед Set: Приводим к одному формату (lowercase, trim), убираем пустоту
    • Set деплицирует: Одна операция, всё работает
    • Разворот в массив: Если нужен массив дальше, используем spread или Array.from()
    • Сохранение порядка: Set гарантирует порядок вставки

    На чём не стоит зацикливаться

    Есть несколько заблуждений, которые прилипают к Set. Первое - что Set это чудо-решение для всего подряд. Нет, это инструмент для конкретной задачи. Второе - что объекты в Set как-то магически дедублицируются. Нет, они сравниваются по ссылке, и это нормально.

    Третье заблуждение - что нужны сложные полифиллы для старых браузеров. Set поддерживается везде, где нужно (IE11+, современные браузеры). Если вы ещё поддерживаете IE10, это вообще отдельная проблема, не только для Set.

    И последнее - что производительность Set магична в каждом случае. Set быстрее именно на проверках уникальности и дедупликации больших объёмов. На маленьких массивах разница незаметна.

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы