Set — это неупорядоченная коллекция уникальных элементов одного типа.
// Сравним, уже известный вам Массив и Сет:
let fruits = ["🍎", "🍌", "🍎"] // ["🍎", "🍌", "🍎"] (дубликат есть)
let fruitsSet: Set<String> = ["🍎", "🍌", "🍎"] // ["🍎", "🍌"] (дубликат удален)
| Тема | Описание |
|---|---|
| 🎯 Основы | Что такое Set и чем он отличается от массива |
| 🤔 Применение | Когда удобно использовать Set вместо других коллекций |
| 🏗️ Создание | Как объявлять и инициализировать Set |
| ➕ Добавление | Как вставлять элементы в Set |
| 🗑️ Удаление | Как удалять элементы из Set |
| 🔍 Проверка | Как быстро проверить наличие элемента |
| 🔄 Перебор | Как проходить по элементам в Set |
| 🧩 Сложные типы | Как хранить в Set структуры и классы |
| 🧮 Операции | Математика множеств: пересечения, объединения |
Представьте, что у вас есть ящик с инструментами 🧰:
Ящик содержит: [🔧, 🔨, 🪛, 🔩]
Главные правила такого ящика:
| Характеристика | Массив (Array) |
Множество (Set) |
|---|---|---|
| Порядок | ✅ Есть (Индексы) | ❌ Случайный |
| Индексы | ✅ Есть (array[2]) |
❌ Нет |
| Дубликаты | ✅ Есть | ❌ Нет |
| Скорость поиска | 🐢 Медленная (проверяет все) | ⚡ Мгновенная |
| Аналогия | Полка с книгами 📚 | Ящик с инструментами 🧰 |
// Массив — порядок важен
let playlist = ["Песня 1", "Песня 2", "Песня 3"]
print(playlist[1]) // Всегда "Песня 2"
// Множество — порядок не важен
let uniqueTracks: Set = ["Песня 1", "Песня 2", "Песня 1"]
print(uniqueTracks) // ["Песня 2", "Песня 1"] (порядок случаен, дубликат удалён)
| Ситуация | Пример | Почему Set? |
|---|---|---|
| Уникальные ID | ID пользователей, заказов | Автоматически удаляет дубликаты |
| Проверка наличия | Есть ли товар на складе? | Мгновенный поиск (contains) |
| Теги / Категории | Хэштеги, Категории товаров | Нет повторов, быстрый поиск |
| Математические операции | Общие друзья, пересечение аудиторий | Встроенные методы (intersection, union) |
⚠️ Запомните: Преимущество Сета – моментальная проверка наличия элемента, только уникальные элементы
// ❌ Плохо: используем массив для уникальных данных
var userIdsArray: [Int] = [101, 102, 103, 101, 104, 102]
// Нужно писать доп. код для удаления дубликатов
// ✅ Оптимально: используем Set
var userIdsSet: Set<Int> = [101, 102, 103, 101, 104, 102]
// Уже [101, 102, 103, 104] — дубликаты удалены автоматически, а доступ к ним моментален
⚠️ Запомните: ещё раз Преимущество Сета – моментальная проверка наличия элемента, только уникальные элементы
// Способ 1: с указанием типа
var emptyStrings: Set<String> = [] // Пустое множество строк
var emptyNumbers: Set<Int> = [] // Пустое множество чисел
// Swift сам понимает тип
var fruits: Set = ["Яблоко", "Мандарин", "Манго"] // Set<String>
var scores: Set = [5, 4, 5, 3, 5] // Set<Int> → [3, 4, 5]
// С явным указанием типа (если не указать явно – Swift подумает, что это Массив, вот он тупой)
var explicitSet: Set<Int> = [1, 2, 3, 3, 3] // [1, 2, 3]
🧠 Важно! Даже если вы укажете дубликаты при создании,
Setавтоматически их удалит:let setWithDuplicates = [1, 1, 2, 2, 3, 3] // [2, 3, 1] (порядок случаен, дубликатов нет (ещё раз повторим))
let vs var// var — можно изменять
var mutableSet: Set = [1, 2, 3]
mutableSet.insert(4) // ✅ Работает!
// let — нельзя изменять
let immutableSet: Set = [1, 2, 3]
immutableSet.insert(4) // ❌ Ошибка!
var fruits: Set = ["🍎 Яблоко", "🍌 Бананчек"]
// Добавляем новый элемент (через insert, append есть только у Массива)
fruits.insert("🍊 Мандарин")
print("Стало: \(fruits)") // ["🍎 Яблоко", "🍌 Бананчек", "🍊 Мандарин"] (порядок случаен)
var shopping: Set = ["🥛 Молоко", "🍞 Хлеб", "🧀 Сыр", "🍎 Яблоко"]
if let removed = shopping.remove("🍞 Хлеб") {
print("Удалили: \(removed)") // Удалили: 🍞 Хлеб
print("Осталось: \(shopping)") // Осталось: ["🥛 Молоко", "🧀 Сыр", "🍎 Яблоко"]
}
shopping.removeAll()
print(shopping) // []
В массиве останутся, только те элементы, которые прошли проверку в .filter...
let numbers: Set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let evenNumbersArray = numbers.filter { number in
number % 2 == 0 // Остаток от деления, нужны только чётные значения (4 % 2 = 0 / 5 % 2 = 1)
}
// evenNumbersArray — это [Int], а не Set<Int> – Обратите внимание
// Превращаем массив обратно в Set
let evenNumbersSet = Set(evenNumbersArray)
⚠️ Запомните: Превратив массив в сет, вы моментально избавитесь от дубликатов
let availableColors: Set = ["🔴 Красный", "🟢 Зеленый", "🔵 Синий", "🟡 Желтый"]
// contains() — проверяет наличие
let hasRed = availableColors.contains("🔴 Красный") // true
let hasBlack = availableColors.contains("⚫ Черный") // false
print("Красный есть? \(hasRed)") // Красный есть? true
print("Черный есть? \(hasBlack)") // Черный есть? false
⚡ Важно! contains в Set работает мгновенно, а в Array — медленно:
- Array: проверяет каждый элемент по очереди O(n)
- Set: моментальный ответ O(1)
let colors: Set = ["🔴", "🟢", "🔵", "🟡"]
// Простой перебор
for color in colors {
print("Цвет: \(color)")
}
// Цвет: 🔵
// Цвет: 🟢
// Цвет: 🔴
// Цвет: 🟡
⚠️ Запомните: Порядок может быть другим при каждом запуске (Элементы в Сете хранятся в случайно порядке)
HashableЧтобы Set мог проверять уникальность, тип должен поддерживать протокол Hashable.
Данные типы данных автоматически поддерживают Hashable:
Int, String, Double, Bool)Hashableenum)Как реализовать протокол Hashable самостоятельно, мы поговорим позже
struct Car: Hashable {
let brand: String
let model: String
let year: Int
}
var cars: Set<Car> = []
let car1 = Car(brand: "BMW", model: "X5", year: 2020)
let car2 = Car(brand: "Audi", model: "Q7", year: 2021)
let car3 = Car(brand: "BMW", model: "X5", year: 2020) // Полная копия car1
cars.insert(car1)
cars.insert(car2)
cars.insert(car3) // Не добавился (уже есть car1)
print("Уникальных машин: \(cars.count)") // 2
Это главная суперсила Set!
Используется не часто, хорошо просто знать, что так можно.
let swiftDevelopers: Set = ["Анна", "Иван", "Ольга", "Петр"]
let kotlinDevelopers: Set = ["Иван", "Петр", "Елена", "Дмитрий"]
intersection)Элементы, которые есть и там, и там
let bothLanguage = swiftDevelopers.intersection(kotlinDevelopers)
print("Знают оба языка: \(bothLanguage)") // ["Иван", "Петр"]
union)Все элементы из обоих множеств, без повторов
let allDevelopers = swiftDevelopers.union(kotlinDevelopers)
print("Все разработчики: \(allDevelopers)")
// ["Анна", "Иван", "Ольга", "Петр", "Елена", "Дмитрий"]
subtracting)Элементы из первого множества, которых нет во втором
let onlySwift = swiftDevelopers.subtracting(kotlinDevelopers)
print("Знают только Swift: \(onlySwift)") // ["Анна", "Ольга"]
symmetricDifference)Элементы, которые есть только в одном из множеств
let exclusive = swiftDevelopers.symmetricDifference(kotlinDevelopers)
print("Знают только один язык: \(exclusive)")
// ["Анна", "Ольга", "Елена", "Дмитрий"]
let groupA: Set = [1, 2, 3]
let groupB: Set = [1, 2, 3, 4, 5]
let groupC: Set = [6, 7, 8]
// Подмножество (все элементы A есть в B?)
print(groupA.isSubset(of: groupB)) // true
// Надмножество (B содержит все элементы A?)
print(groupB.isSuperset(of: groupA)) // true
// Не пересекаются (нет общих элементов?)
print(groupA.isDisjoint(with: groupC)) // true
| Действие | Код | Пояснение |
|---|---|---|
| Создать пустой сет | var set: Set<Int> = [] |
Пустое множество чисел |
| С данными | let set: Set = [1, 2, 3] |
Из трех чисел |
| Добавить | set.insert(4) |
Добавляет 4 |
| Удалить | set.remove(2) |
Удаляет 2 |
| Удалить все | set.removeAll() |
Очищает |
| Проверить наличие | set.contains(3) |
true, если есть 3 |
| Количество | set.count |
Сколько элементов |
| Проверить пустоту | set.isEmpty |
true, если пусто |
// ❌ Это массив, а не множество
let wrong = [1, 2, 3, 3, 3] // [Int] — массив с дубликатами
// ✅ Это множество
let correct: Set = [1, 2, 3, 3, 3] // Set<Int> — без дубликатов
let thisIsSet: Set = ["a", "b", "c"]
let element = thisIsSet[1] // ❌ Ошибка! У Set нет индексов
// ✅ Надо перебирать или использовать .contains
if thisIsSet.contains("b") {
print("b есть в множестве")
}
let thisIsSet: Set = [1, 2, 3]
thisIsSet(4) // ❌ Ошибка! let = неизменяемое
// ✅ Надо использовать var
var mutableSet: Set = [1, 2, 3]
mutableSet.insert(4) // ✅ Работает!
let set: Set = [1, 2, 3, 4, 5]
// Не надейтесь, что элементы будут в порядке 1,2,3,4,5!
for item in set {
print(item) // Может быть: 3, 5, 1, 4, 2
}
| Нужно | Выбор | Почему |
|---|---|---|
| Сохранить порядок | Array |
У массива есть индексы |
| Быстрый поиск | Set |
contains работает мгновенно |
| Уникальные значения | Set |
Автоматически удаляет дубликаты |
| Дубликаты разрешены | Array | Массив разрешает дубликаты |
| Математические операции | Set |
intersection, union и т.д. |
| Доступ по индексу | Array |
array[2] — легко! |
Что будет в множестве после выполнения кода?
let thisIsSet: Set = [1, 2, 2, 3, 3, 3]
print(thisIsSet)
Можно ли получить элемент по индексу из Set?
Что вернет set.contains() если элемента нет?
Какая операция найдет общие элементы двух множеств?
TGUserтелефонном номере, никнейме и роли пользователя (admin, user, guest)enum.
Подумай – почему для роли удобно выбрать enum, а не просто StringВступить / Выйти
Необходимо написать функцию, которая будет проверять есть ли данный в пользователь в списке участников групп.
И если он есть – функция должна возвращать текст Выйти, если пользователя нет в списке – ВступитьРешение можете присылать сюда
Поздравляю! Вы освоили Set (Набор) — фундаментальную структуру данных. Теперь вы готовы к изучению:
| Тема | Описание |
|---|---|
| Словари | Хранят пары “ключ-значение” |
| Массив | Как массивы, но без порядка и без повторов |