Python: коллекции, часть 3/4: объединение коллекций, добавление и удаление элементов

December 21st 2021

1. Объединение строк, кортежей, списков, словарей без изменения исходных


Рассмотрим способы объединения строк, кортежей, списков, словарей без изменения исходных коллекций — когда из нескольких коллекций создаётся новая коллекция того же тип без изменения изначальных.

  1. Объединение строк (string) и кортежей (tuple) возможна с использованием оператора сложения «+»

    str1 = 'abc'
    str2 = 'de'
    str3 = str1 + str2
    print(str3)         # abcde
    
    tuple1 = (1, 2, 3)
    tuple2 = (4, 5)
    tuple3 = tuple1 + tuple2
    print(tuple3)       # (1, 2, 3, 4, 5)
    

  2. Для объединения списков (list) возможны три варианта без изменения исходного списка:

    • Добавляем все элементы второго списка к элементам первого, (аналог метод .extend() но без изменения исходного списка):

      a = [1, 2, 3]
      b = [4, 5]
      c = a + b           
      print(a, b, c)      # [1, 2, 3]  [4, 5]  [1, 2, 3, 4, 5]
      

    • Добавляем второй список как один элемент без изменения исходного списка (аналог метода.append() но без изменения исходного списка):

      a = [1, 2, 3]
      b = [4, 5]
      c = a + [b]
      print(a, b, c)     # [1, 2, 3]  [4, 5]  [1, 2, 3, [4, 5]]
      

  3. Со словарем (dict) все не совсем просто.

    Сложить два словаря чтобы получить третий оператором + Питон не позволяет «TypeError: unsupported operand type(s) for +: 'dict' and 'dict'».

    Это можно сделать по-другому комбинируя методы .copy() и .update():

    dict1 = {'a': 1, 'b': 2}
    dict2 = {'c': 3, 'd': 4}
    dict3 = dict1.copy()
    dict3.update(dict2)
    print(dict3)        	# {'a': 1, 'c': 3, 'b': 2, 'd': 4}
    

    В Питоне 3.5 появился новый более изящный способ:

    dict1 = {'a': 1, 'b': 2}
    dict2 = {'c': 3, 'd': 4}
    dict3 = {**dict1, **dict2}
    print(dict3)        	# {'a': 1, 'c': 3, 'b': 2, 'd': 4}
    

2. Объединение множеств без изменения исходных


Для обоих типов множеств (set, frozenset) возможны различные варианты комбинации множеств (исходные множества при этом не меняются — возвращается новое множество).

image

# Зададим исходно два множества (скопировать перед каждым примером ниже)
a = {'a', 'b'}
b = {    'b', 'c'}	# отступ перед b для наглядности

  1. Объединение (union):

    c = a.union(b)     # c = b.union(a) даст такой же результат	
    # c = a + b        # Обычное объединение оператором + не работает
    		   # TypeError: unsupported operand type(s) for +: 'set' and 'set'
    c = a | b          # Альтернативная форма записи объединения
    print(c)	   # {'a', 'c', 'b'}
    

  2. Пересечение (intersection):

    c = a.intersection(b)    # c = b.intersection(a) даст такой же результат
    c = a & b                # Альтернативная форма записи пересечения
    print(c)                 # {'b'}

    Пересечение более 2-х множеств сразу:
    a = {'a', 'b'}
    b = {     'b', 'c'}
    c = {    'b', 'd'}
    d = a.intersection(b, c)	# Первый вариант записи
    d = set.intersection(a, b, c)   # Второй вариант записи (более наглядный)
    print(d)                        # {'b'}
    

  3. Разница (difference) — результат зависит от того, какое множество из какого вычитаем:

    c = a.difference(b)      # c = a - b другой способ записи дающий тот же результат
    print(c)                 # {'a'}
    c = b.difference(a)      # c = b - a другой способ записи дающий тот же результат
    print(c)                 # {'c'}
    

  4. Симметричная разница (symmetric_difference) Это своего рода операция противоположная пересечению — выбирает элементы из обеих множеств которые не пересекаются, то есть все кроме совпадающих:

    c = b.symmetric_difference(a)   
    # c = a.symmetric_difference(b)       # даст такой же результат
    c = b ^ a                             # Альтернативная форма записи симметричной разницы
    print(c)        		      # {'a', 'c'}
    

3. Объединение списка, словаря и изменяемого множества с изменением исходной коллекции


  1. Для списка

    • Добавляем все элементы второго списка к элементам первого с измением первого списка методом .extend():

      a.extend(b)    # a += b эквивалентно a.extend(b)
      print(a, b)    # [1, 2, 3, 4, 5]  [4, 5]
      

    • Добавляем второй список как один элемент с изменением первого списка методом .append():

       a.append(b)    # a += [b] эквивалентно a.append(b)
       print(a, b)    # [1, 2, 3, [4, 5]]  [4, 5]
      
  2. Для изменения словаря с добавления элементов другого словаря используется метод .update().

    Обратите внимание: для совпадающих ключей словаря при этом обновляются значения:

    dict1 = {'a': 1, 'b': 2}
    dict2 = {'a': 100, 'c': 3, 'd': 4}
    dict1.update(dict2)
    print(dict1)        # {'a': 100, 'c': 3, 'b': 2, 'd': 4}
    

  3. Для изменяемого множества (set) кроме операций, описанных в предыдущем разделе, также возможны их аналоги, но уже с изменением исходного множества — эти методы заканчиваются на _update. Результат зависит от того, какое множество каким обновляем.

    • .difference_update()

      a = {'a', 'b'}
      b = {     'b', 'c'}
      a.difference_update(b)
      print(a, b)         # {'a'} {'b', 'c'}
      a = {'a', 'b'}
      b = {     'b', 'c'}
      b.difference_update(a)
      print(a, b)         # {'a', 'b'} {'c'}
      

    • .intersection_update()

      a = {'a', 'b'}
      b = {     'b', 'c'}
      a.intersection_update(b)
      print(a, b)         # {'b'} {'b', 'c'}
      
      a = {'a', 'b'}
      b = {     'b', 'c'}
      b.intersection_update(a)
      print(a, b)         # {'b', 'a'} {'b'}
      

    • .symmetric_difference_update()

      a = {'a', 'b'}
      b = {     'b', 'c'}
      a.symmetric_difference_update(b)    
      print(a, b)         # {'c', 'a'} {'c', 'b'}
      
      a = {'a', 'b'}
      b = {     'b', 'c'}
      b.symmetric_difference_update(a)
      print(a, b)         # {'a', 'b'} {'c', 'a'}
      

    4 Добавление и удаление элементов изменяемых коллекций


    Добавление и удаление элементов в коллекцию возможно только для изменяемых коллекций: списка (list), множества (только set, не frozenset), словаря (dict). Причём для списка, который является индексированной коллекцией, также важно на какую позицию мы добавляем элемент.

    image

    Примечания:

    • Примеры использования метода .insert(index, element)
      my_list = [1, 2, 3]
      my_list.insert(0, 0)    # index = 0 - вставляем в начало
      print(my_list)          # [0, 1, 2, 3]
      
      my_list.insert(10, 4)   # Индекс выходит за границы списка -  просто добавим в конец
      print(my_list)          # [0, 1, 2, 3, 4]
      
      my_list.insert(-10, -1) # Индекс выходит за границы в минус - добавим в начало
      print(my_list)          # [-1, 0, 1, 2, 3, 4]
      
      my_list = [1, 2, 3]
      my_list.insert(1, 1.5)  # Вставим между 1 и 2 (индексация с нуля!)
      # То есть вставляется на позицию с указанным индексом, а то значение что на ней было 
      # и те что правее - сдвигаются на 1 индекс вправо
      print(my_list)          # [1, 1.5, 2, 3]
      

    • Примеры использования оператора del
      # Работает со списком
      my_list = [1, 2, 3, 4, 5, 6, 7]
      del my_list[1]          # Удаление элемента по индексу
      print(my_list)          # [1, 3, 4, 5, 6, 7]
      del my_list[-3:-1]      # Удаление элементов выбранных срезом
      print(my_list)          # [1, 3, 4, 7]
      # del my_list[10]       # IndexError: list assignment index out of range
      
      # Работает со словарем
      my_dict = {'a': 1, 'b': 2, 'c': 3}
      del my_dict['b']
      print(my_dict)          # {'a': 1, 'c': 3}
      # del my_dict['z']      # KeyError при попытке удалить не сушествующий