Содержание
Возможно, вы помните, что изучали множество и теорию множеств на каком-то этапе вашего образования. Может быть, вы даже помните диаграммы Венна:
Если вам это ни о чем не говорит,не волнуйтесь! Это статья по-прежнему должна быть легкой и понятной для вас.
В математике строгое определение множества может быть абстрактным и трудным для понимания. Практически, однако, набор можно рассматривать просто как четко определенную коллекцию различных объектов, обычно называемых элементами или членами.
Группировка объектов в набор также может быть полезна в программировании, и Python предоставляет для этого встроенный тип набора. Наборы отличаются от других типов объектов уникальными операциями, которые могут быть выполнены над ними.
Вот что вы узнаете из этой статьи: вы увидите, как определять объекты набора в Python и обнаруживать операции, которые они поддерживают. Как и в предыдущих статьях по спискам и словарям, когда вы закончите с этой статьей, вы должны хорошо понимать, когда набор является подходящим. Вы также узнаете о замороженных наборах, которые похожи на наборы, за исключением одной важной детали.
Определение набора
Встроенный тип набора Python имеет следующие характеристики:
- Множества неупорядочены.
- Элементы набора уникальны. Повторяющиеся элементы не допускаются.
- Сам набор может быть изменен, но элементы, содержащиеся в наборе, должны иметь неизменяемый тип.
Давайте посмотрим, что все это значит и как вы можете работать с наборами в Python.
Набор может быть создан двумя способами. Во-первых, вы можете определить набор с помощью встроенной функции set() :
x = set()
В этом случае аргумент является итеративным (это выполнение работ параллельно с непрерывным анализом полученных результатов и корректировкой предыдущих этапов работы.),опять же, на данный момент, подумайте над списком который генерирует список объектов, которые должны быть включены в набор.Это аналогично аргументу , приведенному в методе списка extend() :
>>> x = set(['foo', 'bar', 'baz', 'foo', 'qux']) >>> x {'qux', 'foo', 'bar', 'baz'} >>> x = set(('foo', 'bar', 'baz', 'foo', 'qux')) >>> x {'qux', 'foo', 'bar', 'baz'}
Строки также являются итеративными, поэтому строка также может быть передана в set(). Вы уже видели, что list(s) генерирует список символов в строке s. Аналогично, set(s) генерирует набор символов в s:
>>> s = 'quux' >>> list(s) ['q', 'u', 'u', 'x'] >>> set(s) {'x', 'u', 'q'}
Вы можете видеть, что результирующие множества неупорядочены: исходный порядок, указанный в определении, не обязательно сохраняется. Кроме того, повторяющиеся значения представлены в наборе только один раз, как в случае со строкой " foo "в первых двух примерах и буквой" u " в третьем.
Кроме того, набор может быть определен с помощью фигурных скобок ({}):
x = {, , ..., }
Когда набор определяется таким образом, каждый становится отдельным элементом набора, даже если он является итеративным. Это поведение аналогично поведению метода списка append().
Таким образом, наборы, показанные выше, также могут быть определены следующим образом:
>>> x = {'foo', 'bar', 'baz', 'foo', 'qux'} >>> x {'qux', 'foo', 'bar', 'baz'} >>> x = {'q', 'u', 'u', 'x'} >>> x {'x', 'q', 'u'}
Итого:
- Аргумент set() является итеративным. Он генерирует список элементов, которые должны быть помещены в набор.
- Объекты в фигурных скобках помещаются в набор нетронутыми, даже если они являются итеративными.
Обратите внимание на разницу между этими двумя определениями множества:
>>> {'foo'} {'foo'} >>> set('foo') {'o', 'f'}
Набор может быть пустым. Однако вспомним, что Python интерпретирует пустые фигурные скобки ({}) как пустой словарь, поэтому единственный способ определить пустое множество - это функция set() :
>>> x = set() >>> type(x) >>> x set() >>> x = {} >>> type(x)
Пустое множество ложно в логическом контексте:
>>> x = set() >>> bool(x) Ложно >>> x or 1 1 >>> x and 1 set()
Вы можете подумать, что самые интуитивные наборы будут содержать похожие объекты—например, четные числа или фамилии:
>>> s1 = {2, 4, 6, 8, 10} >>> s2 = {'Смит', 'МакАртур', 'Уилсон', 'Джонсон'}
Однако Python этого не требует. Элементы в наборе могут быть объектами разных типов:
>>> x = {42, 'foo', 3.14159, None} >>> x {None, 'foo', 42, 3.14159}
Не забывайте, что элементы набора должны быть неизменными. Например, запись может быть включена в набор:
>>> x = {42, 'foo', (1, 2, 3), 3.14159} >>> x {42, 'foo', 3.14159, (1, 2, 3)}
Но списки и словари изменчивы, поэтому они не могут быть заданными элементами:
>>> a = [1, 2, 3] >>> {a} Traceback (most recent call last): File "", line 1, in {a} TypeError: unhashable type: 'list' >>> d = {'a': 1, 'b': 2} >>> {d} Traceback (most recent call last): File "", line 1, in {d} TypeError: unhashable type: 'dict'
Установить размер и состав
Функция len() возвращает количество элементов в наборе, а операторы in и not in можно использовать для проверки принадлежности:
>>> x = {'foo', 'bar', 'baz'} >>> len(x) 3 >>> 'bar' in x True >>> 'qux' in x False
Работа на множестве
Многие операции, которые могут быть использованы для других составных типов данных Python, не имеют смысла для наборов. Например, наборы нельзя индексировать или нарезать. Однако Python предоставляет целый набор операций над объектами множества, которые в целом имитируют операции, определенные для математических множеств.
Операторы и Методы
Большинство, хотя и не все, операций с набором в Python можно выполнять двумя различными способами: оператором или методом. Давайте посмотрим, как работают эти операторы и методы, используя в качестве примера объединение множеств.
Учитывая два множества, x1 и x2, объединение x1 и x2 является множеством, состоящим из всех элементов в любом множестве.
Рассмотрим эти два набора:
x1 = {'foo', 'bar', 'baz'} x2 = {'baz', 'qux', 'quux'}
Объединение x1 и x2 - это {'foo', 'bar',' baz',' qux','quux'}.
Примечание: обратите внимание, что элемент "baz", который появляется как в x1, так и в x2, появляется только один раз в объединении. Наборы никогда не содержат повторяющихся значений.
В Python объединение наборов может быть выполнено с помощью оператора | :
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1 | x2 {'baz', 'quux', 'qux', 'bar', 'foo'}
Объединение множеств, также может быть получен с union() метод. Метод вызывается на одном из наборов, а другой передается в качестве аргумента:
>>> x1.union(x2) {'baz', 'quux', 'qux', 'bar', 'foo'}
В приведенных выше примерах оператор и метод ведут себя одинаково. Но между ними есть тонкая разница. При использовании оператора | оба аргумента операции должны быть наборами. Метод union (), с другой стороны, будет принимать любую итерацию в качестве аргумента, преобразовывать ее в набор, а затем выполнять объединение.
Обратите внимание на разницу между этими двумя утверждениями:
>>> x1 | ('baz', 'qux', 'quux') Traceback (most recent call last): File "", line 1, in x1 | ('baz', 'qux', 'quux') TypeError: unsupported operand type(s) for |: 'set' and 'tuple' >>> x1.union(('baz', 'qux', 'quux')) {'baz', 'quux', 'qux', 'bar', 'foo'}
Оба пытаются вычислить объединение x1 и кортежа ('baz',' qux','quux'). Это не удается с помощью оператора|, но успешно выполняется с помощью метода union ().
Доступные операторы и методы
Ниже приведен список операций набора, доступных в Python. Некоторые из них выполняются оператором, некоторые-методом, а некоторые-и тем, и другим. Принцип, описанный выше, обычно применим: там, где ожидается множество, методы обычно принимают в качестве аргумента любую итерацию, но операторы требуют фактических множеств в качестве операндов.
Х1.Союза(х2[, х3 ...])
x1 / x2 [| x3 ...]
Вычислите объединение двух или более множеств.
Установить союз
x1. union (x2) и x1 | x2 оба возвращают набор всех элементов либо в x1, либо в x2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1.union(x2) {'foo', 'qux', 'quux', 'baz', 'bar'} >>> x1 | x2 {'foo', 'qux', 'quux', 'baz', 'bar'}
С помощью оператора или метода можно указать более двух наборов:
>>> a = {1, 2, 3, 4} >>> b = {2, 3, 4, 5} >>> c = {3, 4, 5, 6} >>> d = {4, 5, 6, 7} >>> a.union(b, c, d) {1, 2, 3, 4, 5, 6, 7} >>> a | b | c | d {1, 2, 3, 4, 5, 6, 7}
Результирующий набор содержит все элементы, присутствующие в любом из указанных наборов.
X1. пересечение (x2 [, x3 ...])
x1 & x2 [& x3 ...]
Вычислите пересечение двух или более множеств.
Установить пересечение
X1. пересечение (x2) и x1 & x2 возвращают набор элементов, общих как для x1, так и для x2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1.intersection(x2) {'baz'} >>> x1 & x2 {'baz'}
Вы можете указать несколько наборов с помощью метода и оператора пересечения, как и с помощью set union:
>>> a = {1, 2, 3, 4} >>> b = {2, 3, 4, 5} >>> c = {3, 4, 5, 6} >>> d = {4, 5, 6, 7} >>> a.intersection(b, c, d) {4} >>> a & b & c & d {4}
Результирующий набор содержит только элементы, которые присутствуют во всех указанных наборах.
x1.разница(x2[, x3 ...])
x1 - x2 [- x3 ...]
Вычислите разницу между двумя или более наборами.
Установить разницу
x1. difference (x2) и x1 - x2 возвращают набор всех элементов, которые находятся в x1, но не в x2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1.difference(x2) {'foo', 'bar'} >>> x1 - x2 {'foo', 'bar'}
Другой способ подумать об этом - это x1.difference(x2)и x1 - x2 возвращают набор, который получается, когда какие-либо элементы x2 удаляются или вычитаются из x1.
Еще раз, вы можете указать более двух наборов:
>>> a = {1, 2, 3, 30, 300} >>> b = {10, 20, 30, 40} >>> c = {100, 200, 300, 400} >>> a.difference(b, c) {1, 2, 3} >>> a - b - c {1, 2, 3}
Если указано несколько наборов, операция выполняется слева направо. В приведенном выше примере a - b начала вычисляется, в результате чего {1, 2, 3, 300}. Затем cвычитается из этого набора, оставляя {1, 2, 3}:
x1.symmetric_difference(x2)
x1 ^ x2 [^ x3 ...]
Вычислите симметричную разницу между наборами.
Установить симметричную разницу
Х1.symmetric_difference(Х2), х1 ^ х2 возвращает набор всех элементов либо X1, либо х2, но не оба:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1.symmetric_difference(x2) {'foo', 'qux', 'quux', 'bar'} >>> x1 ^ x2 {'foo', 'qux', 'quux', 'bar'}
Оператор ^ также допускает более двух наборов:
>>> a = {1, 2, 3, 4, 5} >>> b = {10, 2, 3, 4, 50} >>> c = {1, 50, 100} >>> a ^ b ^ c {100, 5, 10}
Как и в случае с оператором разности, когда задано несколько наборов, операция выполняется слева направо.
Любопытно, что хотя оператор ^ допускает несколько множеств, метод. symmetric_difference() этого не делает:
>>> a = {1, 2, 3, 4, 5} >>> b = {10, 2, 3, 4, 50} >>> c = {1, 50, 100} >>> a.symmetric_difference(b, c) Traceback (most recent call last): File "", line 1, in a.symmetric_difference(b, c) TypeError: symmetric_difference() takes exactly one argument (2 given) x1.isdisjoint(x2)
x1.это непересекающиеся(x2)
Определяет, имеют ли два набора какие-либо общие элементы.
x1.is disjoint (x 2) возвращает True, если x1 и x2 не имеют общих элементов:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'baz', 'qux', 'quux'} >>> x1.isdisjoint(x2) Ложь >>> x2 - {'baz'} {'quux', 'qux'} >>> x1.isdisjoint(x2 - {'baz'}) Правда
Если x1.isdisjoint(x2)это Правда, то x1 & x2 это пустой множество:
>>> x1 = {1, 3, 5} >>> x2 = {2, 4, 6} >>> x1.isdisjoint(x2) True >>> x1 & x2 set()
Примечание: Нет оператора, соответствующего методу. isdisjoint ().
x1.issubset(x2)
x1 <= x2
Определите, является ли один набор подмножеством другого.
В теории множеств набор x1 считается подмножеством другого набора, x2 если в него x1 входит каждый элемент x2.
x1.is subset (x2) и x1 <= x2 возвращают Правда, если x1 является подмножеством x2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x1.issubset({'foo', 'bar', 'baz', 'qux', 'quux'}) Правда >>> x2 = {'baz', 'qux', 'quux'} >>> x1 <= x2 Ложь
Множество считается подмножеством самого себя:
>>> x = {1, 2, 3, 4, 5} >>> x.issubset(x) Правда >>> x <= x Правда
Возможно, это кажется странным. Но это соответствует определению—каждый элемент x находится в x.
x1 < x2
Определяет, является ли один набор правильным подмножеством другого.
Правильное подмножество совпадает с подмножеством, за исключением того, что наборы не могут быть идентичными. Набор x1 считается подмножеством другого множества , x2 если каждый элемент x1 находится в x2, а x1 и x2 не равны.
x1 < x2 возвращает Правда, если x1 является правильным подмножеством x2:
>>> x1 = {'foo', 'bar'} >>> x2 = {'foo', 'bar', 'baz'} >>> x1 >> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'bar', 'baz'} >>> x1 < x2 Ложь
Хотя множество считается подмножеством самого себя, оно не является правильным подмножеством самого себя:
>>> x = {1, 2, 3, 4, 5} >>> x >> x < x False
Примечание: оператор = x2
Определите, является ли один набор надмножеством другого.
Надмножество-это обратная сторона подмножества. Множество x1 считается надмножеством другого множества x2, если x1 содержит каждый элемент x2.
x1.is superset (x2) и x1 >= x2 возвращают True, если x1 является надмножеством x2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x1.issuperset({'foo', 'bar'}) Правда >>> x2 = {'baz', 'qux', 'quux'} >>> x1 >= x2 Ложь
Вы уже видели, что набор считается подмножеством самого себя. Набор также считается надмножеством самого себя:
>>> x = {1, 2, 3, 4, 5} >>> x.issuperset(x) True >>> x >= x True x1 > x2
x1 > x2
Определите, является ли один набор правильным надмножеством другого.
Правильное надмножество - это то же самое, что и надмножество, за исключением того, что наборы не могут быть идентичными. Множество x1 считается правильным надмножеством другого множества x2, если x1 содержит каждый элемент X2, а x1 и x2 не равны.
х1 > х2 возвращает Правда, если X1 является надмножеством Х2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'bar'} >>> x1 > x2 Правда >>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'bar', 'baz'} >>> x1 > x2 Ложь
Набор не является полноценным надмножеством самого себя:
>>> x = {1, 2, 3, 4, 5} >>> x > x False
Примечание: Оператор > - это единственный способ проверить, является ли набор правильным надмножеством. Соответствующего метода не существует.
Изменение набора
Хотя элементы, содержащиеся в наборе, должны иметь неизменяемый тип, сами наборы могут быть изменены. Как и вышеописанные операции, существует набор операторов и методов, которые можно использовать для изменения содержимого набора.
Расширенные операторы и методы присваивания
Каждый из перечисленных выше операторов объединения, пересечения, разности и симметричной разности имеет расширенную форму присваивания, которую можно использовать для изменения набора. Для каждого из них также существует соответствующий метод.
Х1.обновление(х2[, х3 ...])
x1 / = x2 [/x3 ...]
Измените набор с помощью объединения.
X1. update (x2) и x1 |= x2 добавляют к x1 любые элементы в x2, которых у x1 еще нет:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'baz', 'qux'} >>> x1 |= x2 >>> x1 {'qux', 'foo', 'bar', 'baz'} >>> x1.update(['corge', 'garply']) >>> x1 {'qux', 'corge', 'garply', 'foo', 'bar', 'baz'}
Х1.intersection_update(х2[, х3 ...])
x1 &= x2 [& x3 ...]
Измените набор по пересечению.
Х1.intersection_update(Х2) и X1 &= Х2 Х1 обновления, сохраняя лишь элементы, найденные в обоих X1 и X2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'baz', 'qux'} >>> x1 &= x2 >>> x1 {'foo', 'baz'} >>> x1.intersection_update(['baz', 'qux']) >>> x1 {'baz'}
Х1.difference_update(х2[, х3 ...])
х1= х2 [| х3 ...]
Изменение установленной разницы.
Х1.difference_update(Х2), х1= х2 Х1 обновление, удаление элементов, найденных в х2:
>>> x1 = {'foo', 'bar', 'baz'} >>> x2 = {'foo', 'baz', 'qux'} >>> x1 -= x2 >>> x1 {'bar'} >>> x1.difference_update(['foo', 'bar', 'qux']) >>> x1 set()
Х1.symmetric_difference_update(Х2)
х1 ^= х2
Измените набор с помощью симметричной разности.
Х1.symmetric_difference_update(Х2), х1 ^= х2 обновление Х1, крепежные элементы либо X1, либо х2, но не оба:
>>> x2 = {'foo', 'baz', 'qux'} >>> >>> x1 ^= x2 >>> x1 {'bar', 'qux'} >>> >>> x1.symmetric_difference_update(['qux', 'corge']) >>> x1 {'bar', 'corge'}
Другие Методы Модификации Наборов
Помимо вышеприведенных расширенных операторов, Python поддерживает несколько дополнительных методов, изменяющих наборы.
х.добавить()
Добавляет элемент в набор.
x. add () добавляет , который должен быть единственным неизменяемым объектом, к x:
>>> x = {'foo', 'bar', 'baz'} >>> x.add('qux') >>> x {'bar', 'baz', 'foo', 'qux'}
х.удалить()
Удаляет элемент из набора.
х.удалить() удаляет от x. Python поднимает исключение, если не в Х:
>>> x = {'foo', 'bar', 'baz'} >>> x.remove('baz') >>> x {'bar', 'foo'} >>> x.remove('qux') Traceback (most recent call last): File "", line 1, in x.remove('qux') KeyError: 'qux'
x. discard ()
Удаляет элемент из набора.
x. discard ()также удаляет из x. Однако, если не находится в x, этот метод спокойно ничего не делает вместо того, чтобы вызвать исключение:
>>> x = {'foo', 'bar', 'baz'} >>> x.discard('baz') >>> x {'bar', 'foo'} >>> x.discard('qux') >>> x {'bar', 'foo'}
x.pop()
Удаляет случайный элемент из набора.
x. pop() удаляет и возвращает произвольно выбранный элемент из x. Если x пуст, x. pop() вызывает исключение:
>>> x = {'foo', 'bar', 'baz'} >>> x.pop() 'bar' >>> x {'baz', 'foo'} >>> x.pop() 'baz' >>> x {'foo'} >>> x.pop() 'foo' >>> x set() >>> x.pop() Traceback (most recent call last): File "", line 1, in x.pop() KeyError: 'pop from an empty set'
x.clear()
Очищает набор.
x. clear() удаляет все элементы из x:
>>> x = {'foo', 'bar', 'baz'} >>> x {'foo', 'bar', 'baz'} >>> >>> x.clear() >>> x set()
Замороженные наборы
Python предоставляет еще один встроенный тип, называемый frozenset, который во всех отношениях точно такой же, как набор, за исключением того, что frozenset является неизменяемым. Вы можете выполнять немодифицирующие операции с frozenset:
>>> x = frozenset(['foo', 'bar', 'baz']) >>> x frozenset({'foo', 'baz', 'bar'}) >>> len(x) 3 >>> x & {'baz', 'qux', 'quux'} frozenset({'baz'})
Но методы, которые пытаются изменить frozenset, терпят неудачу:
>>> x = frozenset(['foo', 'bar', 'baz']) >>> x.add('qux') Traceback (most recent call last): File "", line 1, in x.add('qux') AttributeError: 'frozenset' object has no attribute 'add' >>> x.pop() Traceback (most recent call last): File "", line 1, in x.pop() AttributeError: 'frozenset' object has no attribute 'pop' >>> x.clear() Traceback (most recent call last): File "", line 1, in x.clear() AttributeError: 'frozenset' object has no attribute 'clear' >>> x frozenset({'foo', 'bar', 'baz'})
Если разбираться более глубоко: замороженные наборы и расширенное назначение
Поскольку frozenset является неизменяемым, вы можете подумать, что он не может быть целью расширенного оператора присваивания. Но смотри:>>> f = frozenset(['foo', 'bar', 'baz']) >>> s = {'baz', 'qux', 'quux'} >>> f &= s >>> f frozenset({'baz'})Что это дает?
Python не выполняет расширенные назначения для замороженных наборов на месте. Утверждение x &= s фактически эквивалентно x = x & s. Это не изменение исходного X. Он переназначает x новому объекту, и объект x, на который изначально ссылались, исчезает.Вы можете проверить это с помощью функции id() :
>>> f = frozenset(['foo', 'bar', 'baz']) >>> id(f) 56992872 >>> s = {'baz', 'qux', 'quux'} >>> f &= s >>> f frozenset({'baz'}) >>> id(f) 56992152f имеет другой целочисленный идентификатор после расширенного назначения. Он был переназначен, а не изменен на месте.
Некоторые объекты в Python изменяются на месте, когда они являются целью расширенного оператора присваивания. Но frozensets -нет.
Frozensets полезны в ситуациях, когда вы хотите использовать набор, но вам нужен неизменяемый объект. Например, вы не можете определить набор, элементы которого также являются наборами, потому что элементы набора должны быть неизменяемыми:
>>> x1 = set(['foo']) >>> x2 = set(['bar']) >>> x3 = set(['baz']) >>> x = {x1, x2, x3} Traceback (most recent call last): File "", line 1, in x = {x1, x2, x3} TypeError: unhashable type: 'set'
Если вы действительно чувствуете необходимость определить набор множеств (Эй, это может случиться), вы можете сделать это, если элементы являются замороженными множествами, потому что они неизменны:
>>> x1 = frozenset(['foo']) >>> x2 = frozenset(['bar']) >>> x3 = frozenset(['baz']) >>> x = {x1, x2, x3} >>> x {frozenset({'bar'}), frozenset({'baz'}), frozenset({'foo'})}
Аналогично, вспомните из предыдущего руководства , что ключ словаря должен быть неизменяемым. Вы не можете использовать встроенный тип набора в качестве ключа словаря:
>>> x = {1, 2, 3} >>> y = {'a', 'b', 'c'} >>> >>> d = {x: 'foo', y: 'bar'} Traceback (most recent call last): File "", line 1, in d = {x: 'foo', y: 'bar'} TypeError: unhashable type: 'set'
Если вам нужно использовать наборы в качестве ключей словаря, вы можете использовать замороженные наборы:
>>> x = frozenset({1, 2, 3}) >>> y = frozenset({'a', 'b', 'c'}) >>> >>> d = {x: 'foo', y: 'bar'} >>> d {frozenset({1, 2, 3}): 'foo', frozenset({'c', 'a', 'b'}): 'bar'}
Выводы
В этом уроке вы узнали, как определить объекты set в Python, и познакомились с функциями, операторами и методами, которые можно использовать для работы с наборами.
Теперь вы должны быть знакомы с основными встроенными типами данных, которые предоставляет Python.
Затем вы начнете изучать, как код, который работает с этими объектами, организован и структурирован в программе Python.