8.1.1 Расширенный индексирование
Когда необходимо извлечь подмножества записей из массива, индексы которого нельзя записать как декартово произведение компонентов, можно использовать линейный индексирование вместе с функцией 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)]
Массив с ‘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, …), потому что это позволяет избежать ненужной операции умножения. Кроме того, умножение может быть не определено для объекта, подлежащего дублированию, тогда как индексирование массива всегда определено. Следующий код показывает, как создать двумерный ячейчатый массив из базового элемента, который сам по себе не является скаляром.
{"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 не должен неоднократно изменять размер промежуточного результата.
- : ind = sub2ind (dims, i, j) ¶
- : ind = sub2ind (dims, s1, s2, …, sN) ¶
-
Преобразование индексов в линейные индексы.
Входной dims — это вектор измерений, где каждый элемент является размером массива в соответствующем измерении (см.
size). Остальные входные данные — это скаляры или векторы индексов, которые необходимо преобразовать.Выходной вектор ind содержит преобразованные линейные индексы.
Предыстория: элементы массива можно задать либо с помощью линейного индекса, который начинается с 1 и проходит через количество элементов в массиве, либо с помощью индексов для строки, столбца, страницы и т. д. Функции
ind2subиsub2indпреобразуют между двумя формами.Линейный индекс проходит по измерению 1 (строки), затем по измерению 2 (столбцы), затем по измерению 3 (страницы) и т. д., пока не пронумерует все элементы. Рассмотрим следующие матрицы 3x3:
[(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)матрицы 3x3 в линейные индексы с помощью одного вызова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 (страницы) и т. д., пока не пронумерует все элементы. Рассмотрим следующие матрицы 3x3:
[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в соответствующие индексы матрицы 3x3.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 не выполняло проверку повторно.
Примечание к реализации: строки сначала преобразуются в двойные значения, прежде чем выполняются проверки на допустимость индексов. Если строка не содержит нулевого символа "\0", она всегда будет допустимым индексом.
© 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/v8.1.0/Advanced-Indexing.html