Введение

Встроенный пакет коллекций предоставляет несколько специализированных, гибких типов коллекций, которые одновременно являются высокоэффективными и обеспечивают альтернативы общим типам коллекций dict, list, tuple и set. Модуль также определяет абстрактные базовые классы, описывающие различные типы функциональных возможностей коллекции (такие как MutableSet и ItemsView).

Замечания

В модуле коллекций доступны еще 3 типа, а именно:

  • UserDict
  • UserList
  • UserString

Каждый из них действует как оболочка вокруг связанного объекта, например, UserDict действует как оболочка вокруг объекта типа dict. В каждом случае класс имитирует свой именованный тип. Содержимое экземпляра хранится в объекте обычного типа, доступ к которому осуществляется через атрибут data экземпляра-оболочки. В каждом из этих трех случаев потребность в этих типах была частично вытеснена способностью к подклассу непосредственно из базового типа.

collections.ChainMap


ChainMap - новинка в версии 3.3.  Возвращает новый ChainMap объект с заданным числом карт. Этот объект группирует несколько словарей или других отображений вместе, чтобы создать единое обновляемое представление.

ChainMap’ы полезны для управления вложенными контекстами и наложениями. Пример в мире Python находится в реализации Context класса в шаблонном  движке Джанго. Это полезно для быстрого связывания нескольких отображений, чтобы результат можно было рассматривать как единое целое. Это часто намного быстрее , чем создание нового словаря и запуск несколько update() вызовов.

В любое время, когда у вас имеется цепочка значений поиска, может быть случай для ChainMap. Пример включает в себя наличие заданных пользователем значений и словаря значений по умолчанию. Другим примером являются карты параметров POST и GET найденные в веб - использовании, например, Django или Flask. Благодаря использованию ChainMap можно получить комбинированный представление двух различных словарей.

Список параметров maps организуется от первого-поискового до последнего-поискового. Поисковые запросы последовательно выполняют поиск соответствующих сопоставления, пока не будет найден ключ. Напротив, операции записи, обновления и удаления действуют только при первом сопоставлении.

import collections
# определите 2 словаря с перекрывающимися хотя бы несколькими ключами

dict1 = {'apple': 1, 'banana': 2}
dict2 = {'coconut': 1, 'date': 1, 'apple': 3}

# создайте 2 ChainMap’а с разным порядком этих словарей.
combined_dict = collections.ChainMap(dict1, dict2)
reverse_ordered_dict = collections.ChainMap(dict2, dict1)

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

for k, v in combined_dict.items():
    print(k, v)

>>>Out: coconut 1
	date 1
	apple 1
    	banana 2

for k, v in reverse_ordered_dict.items():
    print(k, v)

>>>Out: apple 3
	banana 2
    	coconut 1

collections.Counter

Счетчик является подклассом словаря , что позволяет легко считать объекты. У него есть полезные методы для работы с частотностью объектов, которые вы считаете.

import collections
counts = collections.Counter([1,2,3]) 

Приведенный выше код создает объект count, который имеет частоты всех элементов, передаваемых в конструктор. Этот пример имеет значение Counter({1: 1, 2: 1, 3: 1})

Примеры конструктора

Счетчик символов

collections.Counter('Happy Birthday')

>>>Out: Counter({'H': 1,
         'a': 2,
         'p': 2,
         'y': 2,
         ' ': 1,
         'B': 1,
         'i': 1,
         'r': 1,
         't': 1,
         'h': 1,
         'd': 1})

Счетчик слов

collections.Counter('I am Sam Sam I am That Sam-I-am That Sam-I-am! I do not like that Sam-I-am'.split())

>>>Out: Counter({'I': 3,
         'am': 2,
         'Sam': 2,
         'That': 2,
         'Sam-I-am': 2,
         'Sam-I-am!': 1,
         'do': 1,
         'not': 1,
         'like': 1,
         'that': 1})

 

Рецепты

c = collections.Counter({'a': 4, 'b': 2, 'c': -2, 'd': 0})

Получить количество отдельных элементов

c['a']

>>>Out: 4

Установить количество отдельных элементов

c['c'] = -3
c

>>>Out: Counter({'a': 4, 'b': 2, 'd': 0, 'c': -3})

Получить общее количество элементов в счетчике (4 + 2 + 0 - 3)

sum(c.values())  #отрицательные числа считаются!

>>>Out: 3

Получить элементы (сохраняются только элементы с положительным счетчиком)

list(c.elements())

>>>Out: ['a', 'a', 'a', 'a', 'b', 'b']

Удалить ключи с 0 или отрицательным значением

c - collections.Counter()

>>>Counter({'a': 4, 'b': 2})

 

Удалить все

c.clear()
c
>>>Out: Counter()

Добавить удалить отдельные элементы

c.update({'a': 3, 'b':3})
c.update({'a': 2, 'c':2})  # добавление к существующему, устанавливает если не существует
c

>>>Out: Counter({'a': 5, 'b': 3, 'c': 2})

c.subtract({'a': 3, 'b': 3, 'c': 3})  # вычитание (неготивные значения разрешены)
c

>>>Out: Counter({'a': 2, 'b': 0, 'c': -1})

collections.defaultdict

collections.defaultdict (default_factory) возвращает подкласс dict, который имеет значение по умолчанию для отсутствующих ключей. Аргумент должен быть функцией, которая возвращает значение по умолчанию при вызове без аргументов. Если нет ничего прошло, по умолчанию None .

state_capitals = collections.defaultdict(str)
state_capitals
>>>Out: defaultdict(str, {})

возвращает ссылку на defaultdict, который создаст строковый объект с его методом default_factory.

Типичное использование defaultdict это использовать один из встроенных типов , такие как str , int , list или dict как default_factory, так как они возвращают пустые типы при вызове без аргументов:

str()

>>>Out: ''

int()

>>>Out: 0

list()
>>>Out: []


 

Вызов defaultdict с ключом, который не существует, не приводит к ошибке, как в обычном словаре.

state_capitals['Alaska']

>>>Out: ''

state_capitals

>>>Out: defaultdict(str, {'Alaska': ''})

Другой пример с int :

fruit_counts = collections.defaultdict(int)
fruit_counts['apple'] += 2  # No errors should occur
fruit_counts

>>>Out: defaultdict(int, {'apple': 2})

fruit_counts['banana']  # No errors should occur

>>>Out: 0

fruit_counts  # A new key is created

>>>Out: default_dict(int, {'apple': 2, 'banana': 0}) 

Обычные словарные методы работают со словарем по умолчанию

 >>> state_capitals['Alabama'] = 'Montgomery'
>>> state_capitals
defaultdict(<class 'str'>, {'Alabama': 'Montgomery', 'Alaska': ''})

 

Использование list в качестве default_factory создаст список для каждого нового ключа.

 >>> s = [('NC', 'Raleigh'), ('VA', 'Richmond'), ('WA', 'Seattle'), ('NC', 'Asheville')]
>>> dd = collections.defaultdict(list)
>>> for k, v in s:
...     dd[k].append(v)
>>> dd
defaultdict(<class 'list'>, 
    {'VA': ['Richmond'], 
     'NC': ['Raleigh', 'Asheville'], 
     'WA': ['Seattle']})

 

collections.deque

Возвращает новый deque объект, который инициализируется слева направо (( используя append()) с данными Iterable. Если итератор не указан, новый deque пуст.

Deques - это обобщение стеков и очередей (название произносится как «deck» и сокращенно означает «двусторонняя очередь»). Двусторонних очереди поддерживает потокобезопасность, память эффективно добавляет и извлекает с обеих сторон deque с приблизительно таким же O (1) производительностью в любом направлении

Хотя объекты списка поддерживают аналогичные операции, они оптимизированы для быстрых операций фиксированной длины и требуют O (n) затрат на перемещение памяти для операций pop (0) и insert (0, v), которые изменяют как размер, так и позицию базового представления данных.

Если maxlen не указаны или None, двусторонние очереди  могут вырасти до произвольной длины. В противном случае, deque ограничена до заданной максимальной длины. После того, как ограниченная длина deque полна, когда добавляются новые элементы, соответствующее количество элементов, отбрасываются с противоположного конца. Запросы ограниченной длины обеспечивают функциональность, аналогичную хвостовому фильтру в Unix. Они также полезны для отслеживания транзакций и других пулов данных, где интерес представляют только самые последние действия.

from collections import deque
d = deque('ghi')                 # создаем новый deque с 3мя элементами
for elem in d:                   # итерируем элементы deque
	print elem.upper()
G
H
I

d.append('j')                    # добавляем новую запись в правую
d.appendleft('f')                # добавляем новую запись в левую часть
d                                # показываем представление deque
deque(['f', 'g', 'h', 'i', 'j'])

d.pop()                       # возвращаем и удаляем самый правый

>>>Out: 'j'

d.popleft()                   # возвращаем и удаляем самый левый элемент

>>>Out: 'f'

list(d)                          # перечисляем содержимое deque

>>>Out: ['g', 'h', 'i']

d[0]                             # смотрим самый левый элемент

>>>Out: 'g'

d[-1]                            # смотрим самый правый элемент
>>>Out: 'i'

list(reversed(d))                # перечисляем содержимое deque в 										 # обратном порядке

>>>Out:  ['i', 'h', 'g']

'h' in d                         # ищем deque

>>>Out: True

d.extend('jkl')                  # добавляем множественные элементы за раз

d

>>>Out: deque(['g', 'h', 'i', 'j', 'k', 'l'])

d.rotate(1)                      # правый поворот
d

>>>Out:  deque(['l', 'g', 'h', 'i', 'j', 'k'])

d.rotate(-1)                     # левый поворот
d

>>>Out: deque(['g', 'h', 'i', 'j', 'k', 'l'])

deque(reversed(d))               # создаем новый deque в обратном

>>>Out: deque(['l', 'k', 'j', 'i', 'h', 'g'])

d.clear()                        # опустошаем deque
d.pop()                          # нельзя извлекать элемент из пустого 									 # deque

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in -toplevel-
    d.pop()
IndexError: pop from an empty deque

d.extendleft('abc')              # extendleft() переворачивает порядок 									 # ввода
d

>>>Out: deque(['c', 'b', 'a']) 

Источник: https://docs.python.org/2/library/collections.html

collections.namedtuple

Определим нового типа Person с использованием namedtuple , как в пример ниже:

Person = namedtuple('Person', ['age', 'height', 'name'])

 

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

Person = namedtuple('Person', 'age, height, name')

 

или же

Person = namedtuple('Person', 'age height name')

 

После определения именованного кортежа можно создать экземпляр, вызвав объект с необходимыми параметрами, например:

dave = Person(30, 178, 'Dave')

 

Именованные аргументы также могут быть использованы:

jack = Person(age=30, height=178, name='Jack S.')

 

Теперь вы можете получить доступ к атрибутам namedtuple:

print(jack.age)

>>>Out: 30

print(jack.name)

>>>Out: 'Jack S.'

Первый аргумент namedtuple конструктора (в нашем примере 'Person' ) является typename . Типично используют одно и то же слово для конструктора и имя типа, но они могут быть разными:

Human = namedtuple('Person',  'age, height, name')
dave = Human(30, 178, 'Dave')
print(dave)  # возвращает объект класса Person

>>>Out: Person(age=30, height=178, name='Dave')

collections.OrderedDict

Порядок ключей в словарях Python произвольный: они не регулируются порядком их добавления.

Например:

d = {'foo': 5, 'bar': 6}
print(d)

>>>Out: {'foo': 5, 'bar': 6}

d['baz'] = 7
print(d)

>>>Out: {'baz': 7, 'foo': 5, 'bar': 6}

d['foobar'] = 8
print(d)

>>>Out: {'baz': 7, 'foo': 5, 'bar': 6, 'foobar': 8}

(Произвольный порядок, подразумеваемый выше, означает, что вы можете получить результаты отличные от результатов показанных выше в примере)

Порядок , в котором появляются ключи - порядок , в котором они будут повторяться, например , с использованием цикла for.

collections.OrderedDict класс предоставляет объекты словаря , которые сохраняют порядок ключей. OrderedDict s могут быть созданы , как показано ниже , с серией упорядоченных элементов (здесь, список пар кортежей ключ-значение):

from collections import OrderedDict
d = OrderedDict([('foo', 5), ('bar', 6)])
print(d)

>>>Out: OrderedDict([('foo', 5), ('bar', 6)])

d['baz'] = 7
print(d)

>>>Out: OrderedDict([('foo', 5), ('bar', 6), ('baz', 7)])

d['foobar'] = 8
print(d)

>>>Out: OrderedDict([('foo', 5), ('bar', 6), ('baz', 7), ('foobar', 8)])

 

Или мы можем создать пустой OrderedDict , а затем добавить элементы:

o = OrderedDict()
o['key1'] = "value1"
o['key2'] = "value2"
print(o)

>>>Out: OrderedDict([('key1', 'value1'), ('key2', 'value2')])

Итерация через OrderedDict позволяет доступ к ключам в порядке их добавления.

Что произойдет, если мы присвоим новое значение существующему ключу?

d['foo'] = 4
print(d)

>>>Out: OrderedDict([('foo', 4), ('bar', 6), ('baz', 7), ('foobar', 8)])

Ключ сохраняет свое первоначальное место в OrderedDict .