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 перед проверкой на допустимость индексов. Если строка не содержит нулевой символ «\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))
создают матрицу 2 × 3 с равными 13 элементами. Это также можно записать как
13(ones (2, 3))
Использование индексирования более эффективно по сравнению с конструкцией кода scalar * ones (M, N, …), поскольку оно избегает ненужной операции умножения. Кроме того, умножение может быть не определено для объекта, подлежащего репликации, в то время как индексирование массива всегда определено. Следующий код демонстрирует, как создать массив ячеек 2 × 3 из базового элемента, который сам по себе не является скаляром.
{"Hello"}(ones (2, 3)) Следует отметить, что ones (1, n) (строчный вектор единиц) приводит к объекту диапазона (с нулевым приращением). Диапазон хранится внутри как начальное значение, приращение, конечное значение и общее количество значений; следовательно, он более эффективен для хранения, чем вектор или матрица единиц, когда число элементов больше 4. В частности, когда ‘r’ — это строчный вектор, выражения
r(ones (1, n), :)
r(ones (n, 1), :)
произведут идентичные результаты, но первое будет значительно быстрее, по крайней мере, для достаточно больших ‘r’ и ‘n’. В первом случае индекс хранится в сжатом виде как диапазон, что позволяет Octave выбрать более эффективный алгоритм обработки выражения.
Общее рекомендация для пользователей, незнакомых с этими техниками, — использовать функцию repmat для репликации меньших массивов в большие, которая использует такие приемы.
Индексирование для повышения производительности ¶
Второе применение индексирования — ускорение кода. Индексирование — это быстрая операция, и его умелое применение может уменьшить необходимость циклов по отдельным элементам массива, что является медленной операцией.
Рассмотрим следующий пример, который создаёт строчный вектор a из 10 элементов, содержащий значения 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–2023 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.2.0/Advanced-Indexing.html