Работа с типизированными массивами целых чисел в Python

Раздел: Списки -> Структуры данных

Основы работы с массивами целых чисел в Python

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

Основной эффективный способ: модуль array

Модуль array предоставляет типизированные массивы, которые хранят элементы одного типа и занимают меньше памяти, чем списки. Для целых чисел используется код типа 'i' (знаковое 32-битное целое) или 'l' (знаковое 64-битное). Основные операции:

import array

# Создание массива из последовательности
arr = array.array('i', [10, 20, 30])
print(arr)  # array('i', [10, 20, 30])

# Добавление элемента
arr.append(40)

# Доступ по индексу
print(arr[0])  # 10

# Изменение элемента
arr[1] = 25

# Удаление последнего элемента
arr.pop()

# Итерация
for x in arr:
    print(x, end=' ')  # 10 25 30

значения списка числа python (итерация по значениям списка чисел в python)

Для создания массива с большими целыми числами используется код 'q' (64-битное знаковое):

arr64 = array.array('q', [2**60, -2**60])
print(arr64)  # array('q', [1152921504606846976, -1152921504606846976])

словарь set python (словарь и set в python)

Типичные ошибки и их решения

  • TypeError: добавление нецелого числа (например, строки). Решение: проверять тип перед добавлением или использовать исключения.
  • OverflowError: значение выходит за пределы выбранного типа (например, 2**31 в 'i'). Решение: использовать код с большей разрядностью ('l' или 'q').
  • ValueError: неверный код типа. Решение: сверяться с документацией ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd').

Как создать динамический массив с возможностью хранения разных типов?

Вариант: список (list)

Список - универсальная структура, может содержать любые объекты, включая целые числа. Он проще в использовании, но занимает больше памяти и медленнее при операциях с большим количеством элементов.

lst = [1, 2, 3]
lst.append(4)
lst[0] = 10
lst.pop()
print(lst)  # [10, 2, 3]

Python dict set (словарь и множество в python)

Список не контролирует типы: можно добавить строку или другой объект, что может привести к ошибкам при последующей обработке.

Проблемы и решения

  • Высокое потребление памяти: каждый элемент - объект Python (28+ байт). Решение: перейти на array или numpy для больших массивов.
  • Смешивание типов: если требуется строгая типизация, следует добавить проверки или использовать array.
  • Скорость: операции вставки/удаления в середине - O(n). Решение: для частых вставок в начало использовать collections.deque, но это уже не массив.

Как производить высокопроизводительные вычисления с массивами целых чисел?

Вариант: NumPy ndarray

NumPy предоставляет многомерные массивы с фиксированным типом и векторизованными операциями. Он незаменим для научных расчётов, но требует установки библиотеки (pip install numpy).

import numpy as np

# Создание одномерного массива
arr = np.array([1, 2, 3], dtype=np.int32)
print(arr)  # [1 2 3]

# Поэлементное сложение
print(arr + 10)  # [11 12 13]

# Среднее значение
print(arr.mean())  # 2.0

# Изменение размера (возвращает новый массив)
arr = np.append(arr, [4, 5])
print(arr)  # [1 2 3 4 5]

типы структур python (типы структур данных в python)

Проблемы и решения

  • Необходимость установки: NumPy не входит в стандартную библиотеку. Решение: использовать array для простых сценариев.
  • Накладные расходы на создание массива: для маленьких массивов list может быть быстрее. Решение: профилировать на реальных данных.
  • Ошибка типов: при создании из списка с разными типами может произойти автоматическое преобразование. Решение: явно указывать dtype.
Как хранить последовательность целых чисел в компактном бинарном формате?

Вариант: bytearray (для байтов 0..255)

Если целые числа не выходят за диапазон 0–255, можно использовать bytearray. Он занимает 1 байт на элемент и поддерживает изменение по индексу.

ba = bytearray([100, 200, 50])
ba.append(255)
ba[0] = 0
print(list(ba))  # [0, 200, 50, 255]

Проблемы и решения

  • Ограниченный диапазон: только беззнаковые 8-битные. Решение: использовать array('B') для того же диапазона с аналогичной экономией.
  • Невозможность хранения отрицательных чисел: для них подойдёт array('b').

Расширенные примеры работы с массивами целых чисел

Многомерные массивы с NumPy

NumPy позволяет легко создавать двумерные массивы целых чисел и выполнять матричные операции:

Пример
import numpy as np

# Создание матрицы 3x3 из целых чисел
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.int16)
print(matrix)
# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]

# Транспонирование
print(matrix.T)

# Поэлементное умножение на 2
print(matrix * 2)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[1 4 7]
 [2 5 8]
 [3 6 9]]
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]

Конвертация между array и list

Метод tolist() преобразует array в обычный список. Обратное преобразование выполняется через конструктор array.array.

Пример
import array

arr = array.array('i', [100, 200, 300])
lst = arr.tolist()
print(lst)  # [100, 200, 300]

# Обратно
del arr
arr = array.array('i', lst)
print(arr)  # array('i', [100, 200, 300])

Сортировка массива array

Модуль array не имеет встроенного метода сортировки, но можно использовать встроенную функцию sorted(), которая возвращает список, или преобразовать в список, отсортировать и создать новый массив.

Пример
import array

arr = array.array('i', [3, 1, 2])
sorted_lst = sorted(arr)
arr_sorted = array.array('i', sorted_lst)
print(arr_sorted)  # array('i', [1, 2, 3])

# Реверс
arr.reverse()
print(arr)  # array('i', [2, 1, 3])

Работа с бинарными файлами

Массивы array можно сохранять и загружать в бинарном формате с сохранением типа.

Пример
import array

# Запись в файл
arr = array.array('i', [10, 20, 30, 40])
with open('ints.bin', 'wb') as f:
    arr.tofile(f)

# Чтение из файла
arr_loaded = array.array('i')
with open('ints.bin', 'rb') as f:
    arr_loaded.fromfile(f, 4)
print(arr_loaded)  # array('i', [10, 20, 30, 40])

Сравнение производительности: list vs array vs numpy

Для больших массивов (миллионы элементов) разница в скорости и памяти существенна. Приведём приблизительные замеры:

Пример
import array, sys, time

# Размер теста
n = 10_000_000

# Список
lst_start = time.time()
lst = [i for i in range(n)]
lst_time = time.time() - lst_start
print(f'List creation: {lst_time:.3f}s, size: {sys.getsizeof(lst)} bytes')

# array
arr_start = time.time()
arr = array.array('i', range(n))
arr_time = time.time() - arr_start
print(f'Array creation: {arr_time:.3f}s, size: {sys.getsizeof(arr)} bytes')

# NumPy (требуется установка)
# import numpy as np
# np_start = time.time()
# np_arr = np.arange(n, dtype=np.int32)
# np_time = time.time() - np_start
# print(f'NumPy creation: {np_time:.3f}s, size: {sys.getsizeof(np_arr)} bytes')
*Результаты будут различаться в зависимости от системы, но обычно array создаётся быстрее списка и занимает в 4-5 раз меньше памяти, NumPy ещё быстрее и компактнее.*

Генерация случайных целых чисел для массива

Для array можно использовать генератор случайных чисел:

Пример
import array, random

random.seed(42)
arr = array.array('i', [random.randint(-100, 100) for _ in range(10)])
print(arr)  # array('i', [74, 34, -53, -44, 33, -63, 48, 28, -2, -25])

Использование memoryview для работы с array

Объект memoryview позволяет работать с внутренним буфером без копирования:

Пример
import array

arr = array.array('i', [1, 2, 3, 4])
mv = memoryview(arr)
print(mv[0])  # 1
mv[1] = 99
print(arr)    # array('i', [1, 99, 3, 4])

# Преобразование в bytes
b = mv.tobytes()
print(b)  # b'\x01\x00\x00\x00c\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'

Массив целых чисел в Python - comments

En
Python массив int (python)