Что такое Set в Dart и как он используется?

Ответ

Set в Dart — это неупорядоченная коллекция уникальных элементов. В отличие от List, Set гарантирует уникальность элементов и обеспечивает быстрый поиск (O(1) в среднем случае).

Основные характеристики:

  • Все элементы уникальны (дубликаты игнорируются)
  • Порядок не гарантируется (кроме LinkedHashSet)
  • Быстрые операции contains(), add(), remove()

Создание Set:

// Set-литерал
Set<String> fruits = {'apple', 'banana', 'orange'};

// Конструктор
Set<int> numbers = Set();
numbers.addAll([1, 2, 3, 3, 2, 1]); // Результат: {1, 2, 3}

// Из другого Iterable
Set<String> uniqueNames = Set.from(['Alice', 'Bob', 'Alice']);
print(uniqueNames); // {Alice, Bob}

Типы Set в Dart:

  1. HashSet (по умолчанию):

    final hashSet = HashSet<int>();
    // Быстрый доступ, порядок не сохраняется
  2. LinkedHashSet (сохраняет порядок вставки):

    final orderedSet = LinkedHashSet<String>();
    orderedSet.addAll(['z', 'a', 'b']);
    print(orderedSet); // {z, a, b} - порядок сохранен
  3. SplayTreeSet (отсортированный):

    final sortedSet = SplayTreeSet<int>((a, b) => b.compareTo(a));
    sortedSet.addAll([3, 1, 4, 1, 5]);
    print(sortedSet); // {5, 4, 3, 1} - отсортировано по убыванию

Полезные операции:

final setA = {1, 2, 3, 4};
final setB = {3, 4, 5, 6};

// Объединение
print(setA.union(setB)); // {1, 2, 3, 4, 5, 6}

// Пересечение
print(setA.intersection(setB)); // {3, 4}

// Разность
print(setA.difference(setB)); // {1, 2}

// Проверка подмножества
print({1, 2}.isSubsetOf(setA)); // true

Практическое использование в Flutter:

// Уникальные ID выбранных элементов
Set<String> selectedIds = {};

void toggleSelection(String id) {
  if (selectedIds.contains(id)) {
    selectedIds.remove(id);
  } else {
    selectedIds.add(id);
  }
  setState(() {});
}

// Фильтрация дубликатов в списке
List<Product> removeDuplicates(List<Product> products) {
  final uniqueIds = Set<String>();
  return products.where((product) {
    return uniqueIds.add(product.id); // add возвращает false если уже есть
  }).toList();
}

Производительность:

  • contains(): O(1) в среднем
  • add()/remove(): O(1) в среднем
  • Итерация: O(n)

Когда использовать Set вместо List:

  • Нужна гарантия уникальности элементов
  • Частые проверки наличия элемента
  • Операции с множествами (объединение, пересечение)
  • Удаление дубликатов из коллекции

Ответ 18+ 🔞

А, Set в Dart, ну это ж просто ёперный театр с уникальностью! Представь себе такую картину: у тесть есть мешок с яблоками, и ты туда пытаешься запихнуть ещё одно такое же яблоко. Set смотрит на тебя, как на идиота, и говорит: «Чувак, ты веришь, что я этого не замечу?» И просто игнорирует твои потуги. В отличие от List, который, как распиздяй, возьмёт всё что дают, хоть десять одинаковых яблок — ему да похуй.

Основная фишка у него вот какая:

  • Все элементы там уникальные — дубликаты он выкидывает нахуй сразу.
  • Порядок, как правило, не гарантирует (ну кроме одного особого случая, о нём ниже).
  • Но зато найти элемент (contains) или добавить/удалить — это ебушки-воробушки, в среднем моментально (O(1)), не то что в списке, где надо всё перебирать.

Создаётся это чудо просто:

// Прям так, литералом
Set<String> фрукты = {'яблоко', 'банан', 'апельсин'};

// Или через конструктор
Set<int> цифры = Set();
цифры.addAll([1, 2, 3, 3, 2, 1]); // И что получится? Правильно, {1, 2, 3}. Всё лишнее — нахуй!

// Из любой другой коллекции, чтоб дубли убрать
Set<String> уникальныеИмена = Set.from(['Анна', 'Боря', 'Анна']);
print(уникальныеИмена); // {Анна, Боря} — второй Анне **доверия ебать ноль**.

А вот тут, бля, внимание, потому что Set'ов есть аж три вида, и они разные, как хуй в пальто и манда с ушами:

  1. HashSet (он же по умолчанию):

    final hashSet = HashSet<int>();
    // Быстрый, шустрый, но порядок элементов может быть какой угодно. Полный **хитрая жопа**.
  2. LinkedHashSet (вот этот — красавчик, если порядок важен):

    final orderedSet = LinkedHashSet<String>();
    orderedSet.addAll(['z', 'a', 'b']);
    print(orderedSet); // {z, a, b} — запомнил, в каком порядке ты их впихнул. Уважительный.
  3. SplayTreeSet (ну это уже полупидор-перфекционист, всё по полочкам):

    final sortedSet = SplayTreeSet<int>((a, b) => b.compareTo(a));
    sortedSet.addAll([3, 1, 4, 1, 5]);
    print(sortedSet); // {5, 4, 3, 1} — сам всё отсортировал по убыванию, как я сказал. **Удивление пиздец**.

Самые соковые операции, где Set реально пизда рулю:

final setA = {1, 2, 3, 4};
final setB = {3, 4, 5, 6};

// Объединение — всё из А и всё из Б, без повторов, ясень хуй
print(setA.union(setB)); // {1, 2, 3, 4, 5, 6}

// Пересечение — только то, что есть и там, и там
print(setA.intersection(setB)); // {3, 4}

// Разность — что есть в А, но нет в Б
print(setA.difference(setB)); // {1, 2}

// Проверка, что одно множество — часть другого
print({1, 2}.isSubsetOf(setA)); // true

Где это применить в Flutter'е, чтобы жизнь мёдом не казалась? Да вот, например:

// Хранение ID выбранных юзером элементов (чтобы не выбрать одно и то же дважды)
Set<String> выбранныеАйдишники = {};

void тумблерВыбора(String id) {
  if (выбранныеАйдишники.contains(id)) {
    выбранныеАйдишники.remove(id); // Развыбрал
  } else {
    выбранныеАйдишники.add(id); // Выбрал
  }
  setState(() {}); // Перерисуйся, сука
}

// Или вот — убрать дубликаты из списка, чтоб не позориться
List<Product> убратьПовторы(List<Product> товары) {
  final уникальныеАйди = Set<String>();
  return товары.where((товар) {
    return уникальныеАйди.add(товар.id); // Метод add возвращает false, если такой id УЖЕ есть в сете. Гениально и просто.
  }).toList();
}

По скорости (чтоб не бздеть попусту):

  • contains(), add(), remove() — в среднем O(1), то есть почти мгновенно.
  • Пройтись по всем элементам — O(n), как и везде.

Итог: когда брать Set?

  • Когда нужно, чтобы всё было уникальное, а дубли — на хуй.
  • Когда постоянно надо проверять, есть ли элемент в коллекции.
  • Когда нужно делать операции объединения, пересечения — тут ему нет равных.
  • Когда из большого овердохуища данных нужно выковырять только уникальные значения.

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