Три основных типа коллекций в Swift - это массивы, словари и наборы. Те из вас, у кого есть некоторый опыт использования массивов и словарей, сталкивались как с мощью, так и с ограничениями использования каждого из них. В этом посте я сосредоточусь на наборах, поскольку они позволяют легко и эффективно собирать информацию из нашей коллекции.

Что такое наборы?

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

При объявлении набора тип должен быть хешируемым, что означает, что если вы используете настраиваемый тип, он должен соответствовать протоколу Hashable. Такие типы, как String, Int, Double и Bool, уже по умолчанию хешируются, поэтому не нуждаются в каких-либо изменениях.

Так как же создать набор, спросите вы? Легкий!

Сначала давайте начнем с синтаксиса. При создании набора шрифтов Swift правильный синтаксис - Set ‹Element›. Элемент представляет собой тип, который будет храниться в наборе.

Вот пример того, как мы можем инициализировать и создать набор:

Важно отметить, что компилятор Swift не может вывести набор типов, как это происходит с массивом. Это означает, что тип всегда должен быть включен при создании экземпляра набора.

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

Массив может содержать несколько значений и не имеет отношения к отдельным значениям, например:

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

Теперь представьте, как вы пытаетесь заполнить тип коллекции методом, который генерирует случайные значения, и вам не нужны дубликаты. Разве набор не был бы удобным способом борьбы с этой проблемой?

Помимо хранения уникальных значений, наборы также могут выполнять ряд операций, характерных для этого типа.

Это включает:

.intersection(_:)
.symmetricDifference(_:)
.union(_:)
.subtracting(_:)

А теперь предположим, что к нам на ужин пришли гости, и мы решили испечь торт и пирожные на десерт. Вот рабочий код, иллюстрирующий эти операции в действии.

Мы можем использовать метод .intersection (_ :) для создания набора, содержащего значения, которые находятся в обоих наборах, например:

Метод .symmetricDifference (_ :) создает набор, содержащий значения, уникальные для каждого набора.

Метод .union (_ :) создает набор, который объединяет значения в обоих наборах без сохранения каких-либо дубликатов.

Если бы мы хотели создать список покупок ингредиентов, необходимых как для нашего торта, так и для пирожных, наш код выглядел бы так:

Наконец, метод .subtracting (_ :) создает набор со значениями, которых нет в указанном наборе.

Членство и равенство

В дополнение к выполнению операций, упомянутых выше, мы также можем проверять членство и равенство множеств. Документация Apple описывает, что это означает, на диаграмме ниже:

На рисунке ниже изображены три набора - a, b и c - с перекрывающимися областями, представляющими элементы, совместно используемые наборами. Набор a является надмножеством набора b, поскольку a содержит все элементы в b. И наоборот, набор b является подмножеством набора a, потому что все элементы в b также содержатся в a. Set b и set c не пересекаются друг с другом, потому что у них нет общих элементов.

Следуя примеру Apple в документации, допустим, у нас есть следующие наборы, может ли кто-нибудь угадать, что является надмножеством и подмножеством?

let houseAnimals: Set = ["dog", "cat"]
let farmAnimals: Set = ["cow", "chicken", "sheep", "dog", "cat"]
let cityAnimals: Set = ["pigeon", "mouse"]

Если не можете, не волнуйтесь, для этого есть способ!

Методы, связанные с членством в наборе и равенством:

==
.isSubset(of:)
.isSuperset(of:)
.isStrictSubset(of:) or isStrictSuperset(of:)
.isDisjoint(with:)

Что отличает эти методы от операций, упомянутых выше, так это то, что они возвращают оператор Bool, описывающий состояние каждого набора.

Например, если мы хотим проверить, равны ли два набора, мы использовали бы оператор ==.

Или, если бы мы хотели проверить, является ли farmAnimals надмножеством houseAnimals, мы бы просто написали это:

Точно так же метод .isSubset (of :) сообщает нам, все ли значения в наборе содержатся в указанном наборе. Примером этого может быть:

Как и метод .isSuperset (of :) и .isSubset (of :), isStrictSubset (of :) и isStrictSuperset (of :) сообщает нам, является ли набор надмножеством или подмножеством, но только если он не равен указанному установленный.

Наконец, .isDisjoint (with :) определяет, имеют ли два набора общие значения.

Заключение

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

Не верите мне? Попробуйте сами! У вас есть все инструменты для начала, и если вам нужна дополнительная информация, взгляните на ресурсы ниже :)

Ресурсы

Быстрая документация

"Переполнение стека"

Блог Coding Explorer - Swift Set Type