[БЕЗ_ЗВУКА] [МУЗЫКА] [МУЗЫКА] Теперь давайте посмотрим на множества — структура данных, которая очень близка математическим множествам. Для тех, кто забыл, что это такое, очень маленький минутный ликбез. Множеством в математике называется набор однотипных элементов, каждый из которых является уникальным. То есть во множестве не может быть двух одинаковых элементов. Основное отношение, которое представляет интерес для множеств, это отношение включения одного множества в другое или наоборот. Множества в программировании работают совершенно аналогичным образом. Множество Set<T> является набором уникальных, с точки зрения равенства на равно равно, элементов типа T. И основная операция — это как раз проверка того, включает ли множество какой-то элемент. Рассмотрим, как множества могут использоваться на практике. Допустим, что мы хотим убрать из какого-то текста слова-паразиты, такие как: типа, как бы, короче. Для наглядности текст будем представлять как список слов, а слова-паразиты перечислим в параметре переменной длины. Пример решения выглядит следующим образом. Для того чтобы со словами-паразитами было удобнее работать, мы делаем из них множество при помощи функции setOf. Можно заметить, что используется уже знакомый нам оператор раскрытия звездочка для передачи в функцию setOf параметра переменной длины, чтобы множество было построено из отдельных слов-паразитов. Затем мы перебираем все слова из текста, и если слово не является словом-паразитом, если его нет в соответствующем множестве, мы добавляем его в список результат. По окончании мы возвращаем результат в returne. Тесты для нашей функции removeFillerWords выглядят вот так. И их структура должна быть вам уже хорошо знакома. Мы проверяем результат работы функции на каких-то входных данных и сравниваем его с эталонным результатом, что должно было получиться. При написании тестов мы активно используем функцию split, которая разбивает строку-получатель на список строк по заданным разделителям. В нашем случае мы разбиваем предложение по пробелам. Если запустить наши тесты, то они успешно пройдут. Тут я не могу не отметить, что у многих из вас опять точно возник вопрос: а зачем в нашем решении вообще использовать множество? Почему мы не могли вместо множества работать с оригинальным массивом слов-паразитов FillerWords? Давайте посмотрим, будет ли работать такое решение на наших тестах. Тесты продолжают проходить. Если немного подумать, станет ясно почему. Массив или список — это практически множество только без обеспечения уникальности элементов, а в нашей задаче эта уникальность в принципе не особо и важна, а даже если и важна, то почему бы не поддерживать эту уникальность внешним относительно структуры данных способом? Тогда наш вопрос вообще меняется на: а зачем в принципе нужны множества? Тут мы с вами впервые знакомимся с таким понятием, как эффективные структуры данных. Решения на основе списка или массива работают, но сложность проверки вхождения элементов в список значительно больше, чем аналогичная сложность для множества. Для списка нам нужно перебрать все элементы, чтобы проверить, есть или нет в списке какой-то элемент. Для множества эта операция работает намного эффективнее. Не вдаваясь в детали того, за счет чего множества достигают такой эффективности, — более подробно вы будете изучать эти вопросы дальше в процессе обучения программированию — можно запомнить одну простую вещь: если вам нужно представить множество элементов, используйте множество set. Кроме операции проверки включает или нет множество какой-то элемент, множество поддерживает и другие операции, например, при помощи функции intersect или union вы можете построить пересечение или объединение двух множеств соответственно ровно по тем же правилам, что и для математических множеств. Вы также можете сложить или вычесть множество с элементом или набором элементов, чтобы получить новое множество с добавленными или удаленными элементами. Что важно отметить: для всех операций уникальность элементов во множестве поддерживается автоматически. Если вы, например, попробуете добавить во множество элемент, который в нем уже есть, то ничего добавлено не будет. Более подробно множества и операции над ними описаны в указанном разделе Reference языка Kotlin. Вы мне, наверное, не поверите, но кроме неизменяемых множеств, которые мы только что рассмотрели, в Kotlin есть и изменяемые множества. Хотя кого я обманываю? Вы уже давно заметили данную закономерность: для какой-то неизменяемой структуры данных в Kotlin есть ее изменяемый аналог. В случае для set это MutableSet<T>. Данный тип расширяет типа обычного Set и добавляет операции модификации. Учитывая, что мы рассматриваем расширение неизменяемого типа изменяемым уже в третий раз, давайте сразу перейдем к примеру. Представим, что вы хотите построить по тексту набор уникальных слов, в нем встречающихся. Текст мы, как и раньше, будем представлять в виде списка слов, и решить эту задачу можно вот так. Результатом является изменяемое множество, которое мы создаем при помощи функции MutableSetOf. Для добавления новых слов в него мы используем функцию Add, и как и раньше, поддержание уникальности делается за нас. В остальном наше решение достаточно простое и понятное и без каких-то дополнительных пояснений. Посмотрим на тесты для нашего решения. Что нового можно из них узнать? Как видно, в отличие от списков или массивов для множеств порядок элементов не является важным для равенства множеств. Причем это верно как для изменяемых, так и для неизменяемых множеств. Это напрямую следует из свойств математических множеств, где равенство работает именно таким образом. Такой перенос свойств объекта из предметной области в программирование, является тем же, чем в программировании занимаются очень и очень часто. Для того чтобы компьютер мог помочь вам в решении какой-либо проблемы, эту проблему сперва следует сформулировать на понятном компьютеру языке. Причем при переводе важно не потерять свойство, характерное для решаемой задачи. Это мы и видим для множеств, которые по мере возможностей повторяют свойства математических множеств. Как научиться этому переносу? К сожалению, ничего лучше кроме практики и опыта до сих пор не придумали. Поэтому не переживайте, если сперва у вас получается не очень. Со временем вы научитесь всему, главное не сдаваться. В завершение разговора о множествах посмотрим, какие дополнительные операции есть у изменяемого множества по сравнению с неизменяемым. Тут все достаточно очевидно для тех, кто внимательно следил за тем, что мы обсуждали раньше. В изменяемое множество можно добавить или удалить элемент или набор элементов при помощи функции add, remove и addAll, removeAll. Кроме того, так как это все же множество, при помощи функции retainAll можно выполнить операцию пересечения множества с каким-то набором элементов. В результате во множестве останутся только элементы из данного набора. Так как множества, списки и массивы очень и очень похожи друг на друга, между всеми этими структурами данных возможны преобразования. Как мы видели раньше, за него отвечает функция toSomething, где в качестве something обычно указывается тот тип, в который мы хотим преобразовать структуру данных. Для множеств интересными являются функции toList, toTypedArray, toSet и toMutableSet, которые превращают множество в соответствующие типы. Более подробно про все это можно прочитать по следующему адресу. [БЕЗ_ЗВУКА]