Работа со значениями в массивах Python: от списков до NumPy

Раздел: Коллекции -> Списки/Массивы

Основной способ: списки Python (list)

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

Список в Python является универсальной коллекцией для хранения любых объектов. Для доступа к элементу используется индекс в квадратных скобках. Индексация начинается с 0.

fruits = ['apple', 'banana', 'cherry']
print(fruits[0])  # apple
print(fruits[1])  # banana
print(fruits[-1]) # cherry (отрицательный индекс)

Python значение массива (значение массива в python)

apple
banana
cherry

Для изменения значения достаточно присвоить новое по индексу:

fruits[1] = 'blueberry'
print(fruits)
['apple', 'blueberry', 'cherry']

Цель

Обеспечить простой и быстрый доступ к элементам коллекции по их позиции. Используется в большинстве скриптов для работы с однородными или разнородными данными.

Ошибка IndexError возникает при обращении к несуществующему индексу. Всегда проверяйте длину списка с помощью len().

nums = [1, 2, 3]
# print(nums[5])  # IndexError: list index out of range
if len(nums) > 5:
    print(nums[5])

Как проверить наличие значения в списке и найти его индекс?

Для проверки существует оператор in, а для получения индекса - метод index().

colors = ['red', 'green', 'blue']
print('green' in colors)          # True
print('yellow' in colors)         # False
print(colors.index('green'))      # 1
# print(colors.index('yellow'))   # ValueError
True
False
1

Цель и случаи использования

Быстрая проверка принадлежности элемента (оператор in работает за O(n) в среднем). Метод index применяется, когда нужно узнать позицию первого вхождения. Полезно при работе с уникальными идентификаторами или конфигурациями.

Метод index() вызывает ValueError, если элемент отсутствует. Перед вызовом следует использовать in или обернуть вызов в try/except.

if 'yellow' in colors:
    idx = colors.index('yellow')
else:
    idx = -1  # или None

Как преобразовать все значения списка по правилу без циклов?

Для этого применяется генератор списка (list comprehension) или функция map(). Они компактнее и быстрее явного цикла.

numbers = [1, 2, 3, 4, 5]
squares = [x**2 for x in numbers]
print(squares)  # [1, 4, 9, 16, 25]

# С условием
even_squares = [x**2 for x in numbers if x % 2 == 0]
print(even_squares)  # [4, 16]
[1, 4, 9, 16, 25]
[4, 16]

Аналог с map():

squares_map = list(map(lambda x: x**2, numbers))
print(squares_map)
[1, 4, 9, 16, 25]

Цель и случаи использования

Когда нужно быстро изменить каждый элемент списка (нормализация, преобразование типов, фильтрация). List comprehension читается и выполняется эффективнее, чем цикл for с append.

При работе с большими списками list comprehension создаёт новый список в памяти. Если требуется экономия памяти, используют генераторное выражение (круглые скобки) и обрабатывают элементы по одному.

large_range = range(10**7)
squares_gen = (x**2 for x in large_range)  # генератор, не хранит все
print(next(squares_gen))  # 0
print(next(squares_gen))  # 1

Как работать с однородными числовыми данными эффективнее, чем списки?

Для числовых массивов фиксированного типа используются модуль array (встроенный) и библиотека NumPy. Они экономят память и позволяют выполнять векторные операции.

Пример с array:

import array
arr = array.array('i', [1, 2, 3, 4])  # 'i' - знаковое целое
arr.append(5)
print(arr[0])       # 1
print(arr)          # array('i', [1, 2, 3, 4, 5])

Пример с NumPy:

import numpy as np
np_arr = np.array([1, 2, 3, 4], dtype=np.float64)
print(np_arr * 2)   # [2. 4. 6. 8.]
print(np_arr.mean()) # 2.5
[2. 4. 6. 8.]
2.5

Цель и случаи использования

array подходит для больших числовых последовательностей, когда нужна только эффективная память и простой доступ. NumPy - для научных расчётов, статистики, линейной алгебры, где важна скорость операций над массивами.

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

Дополнительные приёмы работы со значениями массивов

Копирование списков: поверхностное и глубокое

Присваивание не создаёт копию, а только ссылку. Чтобы получить независимый список, используется срез [:], метод copy() или модуль copy для сложных вложенных структур.

Пример
original = [[1, 2], [3, 4]]
shallow = original[:]        # поверхностная копия
shallow[0][0] = 99
print(original)              # [[99, 2], [3, 4]] - изменён!

import copy
deep = copy.deepcopy(original)
deep[0][0] = 0
print(original)              # [[99, 2], [3, 4]] - не изменился
[[99, 2], [3, 4]]
[[99, 2], [3, 4]]

Для одномерных списков достаточно copy() или [:].

Удаление дубликатов с сохранением порядка

Если важен порядок, используется проход с помощью dict.fromkeys() или OrderedDict (в современных версиях Python достаточно обычного dict).

Пример
items = [1, 2, 2, 3, 1, 4]
unique = list(dict.fromkeys(items))
print(unique)  # [1, 2, 3, 4]
[1, 2, 3, 4]

Этот способ быстрее, чем проверка вхождения во временный список.

Бинарный поиск в отсортированном списке

Для больших отсортированных списков модуль bisect предоставляет эффективный поиск с логарифмической сложностью.

Пример
import bisect
sorted_list = [1, 3, 5, 7, 9]
pos = bisect.bisect_left(sorted_list, 5)  # 2, элемент найден
pos2 = bisect.bisect_left(sorted_list, 4) # 2, место для вставки
print(pos, pos2)
2 2

Полезно для диапазонных запросов и поддержания отсортированного списка.

Использование collections.deque как двусторонней очереди

Для добавления и удаления элементов с обоих концов deque эффективнее списка.

Пример
from collections import deque
dq = deque([1, 2, 3])
dq.appendleft(0)
dq.append(4)
print(dq)  # deque([0, 1, 2, 3, 4])
dq.popleft()  # 0
dq.pop()      # 4
deque([0, 1, 2, 3, 4])

Векторизация вычислений с NumPy

NumPy выполняет операции над массивами на уровне C, что значительно быстрее циклов Python.

Пример
import numpy as np
big = np.arange(10**6)  # массив от 0 до 999999
# Умножение каждого элемента на 2 (векторизованная операция)
result = big * 2
print(result[:5])  # первые 5 элементов: [0 2 4 6 8]
[0 2 4 6 8]

Также доступны универсальные функции (ufunc), агрегации и операции над осями.

Ошибки при изменении списка во время итерации

Не следует удалять или добавлять элементы в список, одновременно проходя по нему циклом for. Это приводит к пропуску элементов или индексам вне границ.

Пример
lst = [1, 2, 3, 4, 5]
# Неправильно: for x in lst: lst.remove(x)
# Правильный подход - итерация по копии:
for x in lst[:]:
    if x % 2 == 0:
        lst.remove(x)
print(lst)  # [1, 3, 5]
[1, 3, 5]

Или использование спискового включения для фильтрации.

Значение массива в Python - comments

En
Python значение массива (python)