Найти в Дзене
ZDG

Коллекции, часть 3: Множества

Другие части: массивы, итераторы, списки, ассоциативные массивы, деревья

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

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

Давайте посмотрим на тип коллекции "Множество".

Множество понимается как математический термин. То есть оно содержит какие-то элементы... ну да, и массив тоже содержит какие-то элементы, и что? Множество, по своему определению, не может содержать два одинаковых элемента, а массив может. Кроме того, элементы во множестве расположены без определенного порядка. Вернее сказать, они вообще никак не расположены, они там просто есть, ну если в математическом смысле. Когда мы в математике говорим, что множество A содержит число а, то мы не уточняем, в каком именно месте множества находится это число. Оно там просто есть, понятие "место" не имеет смысла.

Это множество, потому что его элементы уникальны.
Это множество, потому что его элементы уникальны.

Хорошо, это так в математике, а зачем в программировании потребовалось создавать коллекцию "Множество" и специально делать так, чтобы элементы в нём были в беспорядке? Ведь каждый элемент занимает физическую память, и какой-то порядок в этой памяти всё равно будет.

Ну конечно, никто специально не вводил беспорядок. То, что элементы не упорядочены, означает лишь одно – данный тип коллекции не гарантирует, что при переборе его элементов они всегда будут перебираться в каком-то определенном порядке. Не гарантирует. Вот и всё.

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

Так и что делать с множествами? А делать можно всё, что обычно делают с множествами: добавлять и удалять элементы, делать объединение и пересечение множеств, узнавать, принадлежит ли элемент множеству. И во-первых, поведение множества будет гарантированно корректным (то есть в него нельзя будет добавить одинаковый элемент дважды), и во-вторых, просто используя тип "Множество", мы даём понять и себе и другим, что наша задача связана именно с множествами, а не просто с какими-то массивами, хотя то же самое можно было бы наколхозить с помощью массивов.

Давайте посмотрим, что нам предлагают языки Python и JavaScript на тему множеств (повторюсь как всегда – мы не учим языки, мы учим принципы):

Python

Множество в Питоне записывается с помощью фигурных скобок:

mySet = {"apple", "banana", "cherry"}

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

mySet = set(("apple", "banana", "cherry"))

Здесь в конструктор множества set() передается список исходных элементов в виде... списка.

JavaScript (и примерно так же Java)

Здесь множество создается как объект класса Set (множество), в конструктор которого передаются исходные данные для множества – в данном случае массив. Класс Set уже определен в языке, его писать не надо.

var mySet = new Set(["apple", "banana", "cherry"]);

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

Python

  • mySet.append(elem) – добавить элемент
  • mySet.remove(elem) – удалить элемент
  • mySet.union(mySet2) – объединить с множеством mySet2

JavaScript

  • mySet.add(elem) – добавить элемент
  • mySet.delete(elem) – удалить элемент
  • mySet.has(elem) – проверить наличие элемента

Питону нужно сделать похвалу за то, что в его интерфейсе множества есть метод union() – объединение множеств. А также методы intersection(), issuperset() и issubset(), то есть всё, что ожидается от интерфейса множества. А иначе зачем вообще всё это затевать? В Java тоже есть кое-что, правда методы называются по-другому. А вот в JavaScript этого нет, поэтому в случае чего придётся нужные методы писать руками. Не бог весть какая сложная работа, но странно, что функционал изначально такой убогий.

Что касается проверки наличия элемента во множестве, то в JavaScript это делается через метод множества has(element):

if (mySet.has("banana")) ...

а в Питоне языковой конструкцией in:

if "banana" in mySet ...

Вот вкратце и всё о множествах. Открывайте документацию по языку, который учите, ищите главу "множества" и смотрите полный список методов. Если же такой главы нет, попробуйте реализовать класс "Множество" самостоятельно.

А мы продолжим рассматривать другие типы коллекций в следующих выпусках.

Наука
7 млн интересуются