8.1.1 Расширенная индексация
Цепочечная индексация
Octave позволяет использовать повторяющиеся (цепочечные) индексные выражения для извлечения подмножеств массива одной командой без необходимости создавать промежуточные переменные. Это упрощает написание кода со сложными операциями индексации или с несколькими методами индексации. В следующем примере показаны два эквивалентных способа извлечения элементов по индексам:
A = reshape (1:16, 4, 4);
B = A(2:4, 2:3);
C = B(3:5);
D = C( [ true, false, true ] )
⇒ D = [ 8, 11 ]
D = A(2:4, 2:3)(3:5)([ true, false, true ])
⇒ D = [ 8, 11 ] Цепочечная индексация неизбежно будет медленнее одного индексного выражения, дающего тот же результат, но обычно она вычислительно эффективнее, чем выполнение нескольких отдельных операций индексации с присваиванием промежуточных переменных.
Обратите внимание, что цепочечная индексация совместима только с выражениями в правой части и не может использоваться в левой части операций присваивания.
Преобразование компонентных индексов в линейные
Когда необходимо извлечь подмножества элементов массива, индексы которых нельзя записать как декартово произведение компонент, можно использовать линейную индексацию вместе с функцией sub2ind. Например:
A = reshape (1:8, 2, 2, 2) # Create 3-D array A = ans(:,:,1) = 1 3 2 4 ans(:,:,2) = 5 7 6 8 A(sub2ind (size (A), [1, 2, 1], [1, 1, 2], [1, 2, 1])) ⇒ ans = [A(1, 1, 1), A(2, 1, 2), A(1, 2, 1)]
-
:
ind =sub2ind(dims, i, j) -
:
ind =sub2ind(dims, s1, s2, …, sN) -
Преобразует индексы-компоненты в линейные индексы.
Входной аргумент dims — это вектор размерностей, каждый элемент которого задаёт размер массива в соответствующей размерности (см.
size). Остальные входные аргументы — скаляры или векторы индексов-компонент, которые нужно преобразовать.Выходной вектор ind содержит преобразованные линейные индексы.
Справка: Элементы массива можно задавать либо линейным индексом, начинающимся с 1 и доходящим до числа элементов массива, либо индексами-компонентами строки, столбца, страницы и т. д. Функции
ind2subиsub2indвыполняют взаимное преобразование этих двух форм.Линейная индексация проходит по размерности 1 (строки), затем по размерности 2 (столбцы), затем по размерности 3 (страницы) и т. д., пока не будут пронумерованы все элементы. Рассмотрим следующие матрицы размером 3 на 3:
[(1,1), (1,2), (1,3)] [1, 4, 7] [(2,1), (2,2), (2,3)] ==> [2, 5, 8] [(3,1), (3,2), (3,3)] [3, 6, 9]
В левой матрице указаны кортежи индексов-компонент для каждого элемента матрицы. В правой матрице показаны линейные индексы той же матрицы.
В следующем примере показано, как преобразовать двумерные индексы
(2,1)и(2,3)матрицы размером 3 на 3 в линейные индексы одним вызовомsub2ind.s1 = [2, 2]; s2 = [1, 3]; ind = sub2ind ([3, 3], s1, s2) ⇒ ind = 2 8
-
:
[s1, s2, …, sN] =ind2sub(dims, ind) -
Преобразует линейные индексы в индексы-компоненты.
Входной аргумент dims — это вектор размерностей, каждый элемент которого задаёт размер массива в соответствующей размерности (см.
size). Второй входной аргумент ind содержит линейные индексы, которые нужно преобразовать.Выходные аргументы s1, …, sN содержат преобразованные индексы-компоненты.
Справка: Элементы массива можно задавать либо линейным индексом, начинающимся с 1 и доходящим до числа элементов массива, либо индексами-компонентами строки, столбца, страницы и т. д. Функции
ind2subиsub2indвыполняют взаимное преобразование этих двух форм.Линейная индексация проходит по размерности 1 (строки), затем по размерности 2 (столбцы), затем по размерности 3 (страницы) и т. д., пока не будут пронумерованы все элементы. Рассмотрим следующие матрицы размером 3 на 3:
[1, 4, 7] [(1,1), (1,2), (1,3)] [2, 5, 8] ==> [(2,1), (2,2), (2,3)] [3, 6, 9] [(3,1), (3,2), (3,3)]
В левой матрице указаны линейные индексы каждого элемента матрицы. В правой матрице показаны кортежи индексов-компонент той же матрицы.
В следующем примере показано, как преобразовать линейные индексы
2и8в соответствующие индексы-компоненты матрицы размером 3 на 3.ind = [2, 8]; [r, c] = ind2sub ([3, 3], ind) ⇒ r = 2 2 ⇒ c = 1 3Если число выходных индексов-компонент превышает число размерностей, лишним размерностям присваивается значение
1. С другой стороны, если указано меньше индексов-компонент, чем размерностей, лишние размерности объединяются в последнюю запрошенную размерность. Для наглядности рассмотрим следующие примеры:ind = [2, 8]; dims = [3, 3]; ## same as dims = [3, 3, 1] [r, c, s] = ind2sub (dims, ind) ⇒ r = 2 2 ⇒ c = 1 3 ⇒ s = 1 1 ## same as dims = [9] r = ind2sub (dims, ind) ⇒ r = 2 8
-
:
tf =isindex(ind) -
:
tf =isindex(ind, n) -
Возвращает true, если ind является допустимым индексом.
Допустимыми индексами являются положительные целые числа (в том числе числа вещественного типа данных) или логические массивы.
Если указан аргумент n, он задаёт максимальный размер индексируемой размерности. По возможности результат внутренней проверки кэшируется, чтобы при последующей индексации с использованием ind проверку не выполнять повторно.
Примечание по реализации: перед проверкой допустимости индексов строки преобразуются в значения типа double. Если строка не содержит символ NULL "\0", она всегда будет допустимым индексом.
Число компонент не совпадает с числом размерностей
Массив с ‘nd’ размерностями можно индексировать выражением, содержащим от 1 до ‘nd’ компонент. В обычном и наиболее распространённом случае число компонент ‘M’ совпадает с числом размерностей ‘nd’. В этом случае применяются обычные правила индексации, и каждая компонента соответствует своей размерности массива.
Однако если число компонент индексации превышает число размерностей (M > nd), все лишние компоненты должны быть равны единице (1). Кроме того, если M < nd, поведение эквивалентно изменению формы входного объекта с объединением конечных nd - M размерностей в последнюю индексную размерность M. Таким образом, результирующий объект будет иметь число размерностей, соответствующее индексному выражению, а не исходному объекту. Это происходит всякий раз, когда число размерностей индекса больше единицы (M > 1), поэтому специальные правила линейной индексации не применяются. Проще всего понять это на примере:
A = reshape (1:8, 2, 2, 2) # Create 3-D array A = ans(:,:,1) = 1 3 2 4 ans(:,:,2) = 5 7 6 8 ## 2-D indexing causes third dimension to be merged into second dimension. ## Equivalent array for indexing, Atmp, is now 2x4. Atmp = reshape (A, 2, 4) Atmp = 1 3 5 7 2 4 6 8 A(2,1) # Reshape to 2x4 matrix, second entry of first column: ans = 2 A(2,4) # Reshape to 2x4 matrix, second entry of fourth column: ans = 8 A(:,:) # Reshape to 2x4 matrix, select all rows & columns, ans = Atmp
Обратите внимание на элегантное использование двойного двоеточия вместо вызова функции reshape.
Дублирование массивов
Ещё один способ расширенного применения линейной индексации — создание массивов, заполненных одним значением. Для этого можно индексировать скаляр значениями индекса, равными единице. Результатом будет объект с размерностями индексного выражения, каждый элемент которого равен исходному скаляру. Например, следующие инструкции
a = 13; a(ones (1, 4))
создают вектор-строку из четырёх элементов, каждый из которых равен 13.
Аналогично, индексируя скаляр двумя векторами единиц, можно создать матрицу. Следующие инструкции
a = 13; a(ones (1, 2), ones (1, 3))
создают матрицу размером 2x3, все элементы которой равны 13. Это также можно было бы записать так:
13(ones (2, 3))
Использовать индексацию эффективнее, чем конструкцию кода scalar * ones (M, N, …), поскольку это позволяет избежать ненужной операции умножения. Кроме того, умножение может быть не определено для дублируемого объекта, тогда как индексация массива всегда определена. В следующем примере показано, как создать ячеечный массив размером 2x3 из базового элемента, который сам по себе не является скаляром.
{"Hello"}(ones (2, 3)) Следует отметить, что ones (1, n) (вектор-строка из единиц) возвращает объект диапазона (с нулевым шагом). Диапазон хранится внутри системы как начальное значение, шаг, конечное значение и общее число значений; поэтому при количестве элементов больше 4 он занимает меньше памяти, чем вектор или матрица единиц. В частности, если ‘r’ — вектор-строка, выражения
r(ones (1, n), :)
r(ones (n, 1), :)
дадут одинаковые результаты, но первое будет значительно быстрее, по крайней мере если ‘r’ и ‘n’ достаточно велики. В первом случае индекс хранится в сжатом виде как диапазон, что позволяет Octave выбрать более эффективный алгоритм обработки выражения.
Пользователям, не знакомым с этими приёмами, рекомендуется использовать функцию repmat для дублирования небольших массивов с целью получения массивов большего размера; эта функция использует подобные приёмы.
Индексация для повышения производительности
Индексацию также используют для ускорения кода. Индексация выполняется быстро, и её разумное применение позволяет сократить необходимость перебора отдельных элементов массива, который выполняется медленно.
Рассмотрим следующий пример, в котором создаётся вектор-строка из 10 элементов a со значениями a(i) = sqrt (i).
for i = 1:10 a(i) = sqrt (i); endfor
Создавать вектор с помощью такого цикла довольно неэффективно. В этом случае гораздо эффективнее было бы использовать выражение
a = sqrt (1:10);
которое полностью исключает цикл.
Если избежать цикла невозможно или необходимо объединить несколько значений в матрицу большего размера, обычно быстрее сначала задать размер матрицы (предварительно выделить память), а затем вставить элементы с помощью команд индексации. Например, для заданной матрицы a,
[nr, nc] = size (a); x = zeros (nr, n * nc); for i = 1:n x(:,(i-1)*nc+1:i*nc) = a; endfor
значительно быстрее, чем
x = a; for i = 1:n-1 x = [x, a]; endfor
поскольку Octave не приходится многократно изменять размер промежуточного результата.
Дополнительные рекомендации по повышению производительности см. в разделе Векторизация и ускорение выполнения кода.
© 1996–2026 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v9.4.0/Advanced-Indexing.html