{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c8ab769e",
   "metadata": {},
   "source": [
    "# Множества #"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "448cade2",
   "metadata": {},
   "source": [
    "Следующей структурой данных, о которой мы с вами поговорим, являются множества.\n",
    "\n",
    "Множества позволяют вам хранить в неупорядоченном виде набор уникальных объектов. Чтобы определить пустое множество, можно просто воспользоваться литералом `set`, определить `empty_set`, или использовать фигурные скобочки, чтобы определить `number_set`, в котором уже содержатся какие-то числа."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a6f9836a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{1, 2, 3, 4, 5}\n"
     ]
    }
   ],
   "source": [
    "empty_set = set()\n",
    "number_set = {1, 2, 3, 3, 4, 5}\n",
    "\n",
    "print(number_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f6f1403",
   "metadata": {},
   "source": [
    "Обратите внимание, мы пытаемся с вами добавить в `number_set` две тройки и у нас ничего не получится, потому что Python гарантирует вам то, что в множестве содержатся уникальные элементы.\n",
    "\n",
    "Это достигается с помощью уже знакомой функции хеширования. Также очень легко и быстро проверить, содержится ли какое-то значение в нашем множестве. Делается это с помощью оператора `in`, и проверка тоже выполняется за константное время. \n",
    "\n",
    "Например, двойка, очевидно, содержится в нашем сете."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "77fec4ef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 in number_set"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31bc07a9",
   "metadata": {},
   "source": [
    "Давайте создадим два множества, `odd_set` и `even_set`, в котором будут содержаться значения, чётное и нечётное число от 0 до 10. Делаем мы это с помощью цикла, и в цикле добавляем элементы множества. Множества являются изменяемой структурой данных, поэтому мы можем это делать с помощью встроенного метода `add`. Мы проверяем чётное и нечётное число и добавляем это число в соответствующее множество."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d44dcf28",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{1, 3, 5, 7, 9}\n",
      "{0, 2, 4, 6, 8}\n"
     ]
    }
   ],
   "source": [
    "odd_set = set()\n",
    "even_set = set()\n",
    "\n",
    "for number in range(10):\n",
    "    if number % 2:\n",
    "        odd_set.add(number)\n",
    "    else:\n",
    "        even_set.add(number)\n",
    "        \n",
    "print(odd_set)\n",
    "print(even_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc80a0b8",
   "metadata": {},
   "source": [
    "Множества, как и предполагает их название, поддерживают математические операции над множествами. Например, мы можем использовать объединения, знакомые вам из курса математики, и получить все значения, которые содержатся как в чётном множестве, так и в нечётном множестве.\n",
    "\n",
    "Очевидно, это все значения, потому что все числа от 0 до 10 являются либо чётными, либо нечётными."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fcf03b2b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}\n"
     ]
    }
   ],
   "source": [
    "union_set = odd_set | even_set\n",
    "union_set = odd_set.union(even_set)\n",
    "\n",
    "print(union_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48e027f6",
   "metadata": {},
   "source": [
    "Точно так же мы можем брать пересечение множеств. Очевидно, что пересечение чётных и нечётных чисел от 0 до 10, да и любых чётных и нечётных чисел - это пустое множество."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "afae36d1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "set()\n"
     ]
    }
   ],
   "source": [
    "intersection_set = odd_set & even_set\n",
    "intersection_set = odd_set.intersection(even_set)\n",
    "\n",
    "print(intersection_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e62260b6",
   "metadata": {},
   "source": [
    "Также мы можем использовать разность из теории множеств и получить все значения, которые содержатся в одном множестве, но не содержатся в другом множестве. Делается это с помощью оператора минус или встроенного метода `difference`. Очевидно, что в множестве `odd_set` содержатся все элементы, которые не содержатся в множестве `even_set`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "af062911",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{1, 3, 5, 7, 9}\n"
     ]
    }
   ],
   "source": [
    "difference_set = odd_set - even_set\n",
    "difference_set = odd_set.difference(even_set)\n",
    "\n",
    "print(difference_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8117277",
   "metadata": {},
   "source": [
    "Существует также симметрическая разность, которую можно получить с помощью шапочки или с помощью метода `symmetric_difference`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f594748a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}\n"
     ]
    }
   ],
   "source": [
    "symmetric_difference_set = odd_set ^ even_set\n",
    "symmetric_difference_set = odd_set.symmetric_difference(even_set)\n",
    "\n",
    "print(symmetric_difference_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ddfb3604",
   "metadata": {},
   "source": [
    "Так как множества являются изменяемой структурой данных, мы можем не только добавлять туда элементы, но и удалять их. Делается это с помощью метода `remove`, которому мы передаем значение, которое мы хотим удалить из множества. Например, мы можем удалить 2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "dec76d51",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0, 4, 6, 8}\n"
     ]
    }
   ],
   "source": [
    "even_set.remove(2)\n",
    "\n",
    "print(even_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4514890",
   "metadata": {},
   "source": [
    "Если мы хотим удалить какое-то случайное значение, можно использовать метод `pop`, который просто вернет какое-то значение из нашего множества. Мы точно не знаем какое."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c1d74063",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "even_set.pop()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35a57ceb",
   "metadata": {},
   "source": [
    "Так как множества являются изменяемой структурой данных, очевидно, у них существует аналог, который неизменяем. Существует `frozenset`, который гарантирует вам уникальность элементов и ведет себя точно так же, как и множества, но мы не можем добавлять туда элементы или удалять их. Например, мы можем определить множество `frozen` и попытаться в него добавить `Olaf'а`. У нас ничего не выйдет, потому что `frozenset` неизменяемый, у него нет метода `add`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d393d0ec",
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'frozenset' object has no attribute 'add'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-11-23adb5d17543>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mfrozen\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfrozenset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"Anna\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Elsa\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Kristoff\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mfrozen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Olaf\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'frozenset' object has no attribute 'add'"
     ]
    }
   ],
   "source": [
    "frozen = frozenset([\"Anna\", \"Elsa\", \"Kristoff\"])\n",
    "\n",
    "frozen.add(\"Olaf\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f074172b",
   "metadata": {},
   "source": [
    "Итак, мы с вами обсудили множества, которые являются неупорядоченным набором уникальных объектов. А также множества можно изменять, то есть добавлять и удалять оттуда элементы. Мы легко можем проверить, существует ли какое-то значение в нашем множестве с помощью оператора `in`; также множества поддерживают операции над множествами, знакомые вам из курса математики. Давайте попробуем решить задачку на множества."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
