Как я могу индексировать несколько сегментов массива одновременно без цикла? - PullRequest
1 голос
/ 01 мая 2019

Я хочу изменить значение в столбце 2 на основе значений в столбце 1 в одном массиве (main), используя начальный и конечный индексы из другого массива (conditions).
В conditions столбец 1 содержит начальный индекс, столбец 2 - конечный индекс.

main = zeros(8, 2);
main(:, 1) = 1:8;
conditions = [2, 3; 6, 8]

main =

     1     0
     2     0
     3     0
     4     0
     5     0
     6     0
     7     0
     8     0

conditions =

     2     3
     6     8

Я знаю, как сделать это с помощью цикла (показано ниже), но ищу более быстрый метод.

for ii = 1:size(conditions, 1)
    main(main(:, 1) >= conditions(ii, 1) & main(:, 1) <= conditions(ii, 2), 2) = 1;
end

main =

     1     0
     2     1
     3     1
     4     0
     5     0
     6     1
     7     1
     8     1

Выполнение main(main(:, 1) >= conditions(:, 1) & main(:, 1) <= conditions(:, 2), 2) = 1 приводит к ошибке Matrix dimensions must agree.

Есть ли метод без петель?

Ответы [ 2 ]

3 голосов
/ 01 мая 2019

Ваша попытка почти верна. Если вы транспонируете conditions, то вы будете сравнивать столбец main со строкой conditions, что приведет к тому, что MATLAB выполнит неявное одноэлементное расширение, что даст выход матрицы. Затем эту матрицу можно свернуть, используя any.

main = zeros(8, 2);
main(:, 1) = 1:8;
conditions = [2, 3; 6, 8];

index = (main(:,1) >= conditions(:, 1).') & (main(:, 1) <= conditions(:, 2).');
index = any(index,2);
main(index,2) = 1;

(для ясности я разделил код на 3 строки, но, конечно, все они могут быть одной строкой.)


Обратите внимание, что для версий MATLAB до R2016b этот код не будет работать, вместо этого вам нужно будет использовать bsxfun:

index = bsxfun(@ge,main(:,1),conditions(:, 1).') & bsxfun(@le,main(:, 1),conditions(:, 2).');
3 голосов
/ 01 мая 2019

ПРИМЕЧАНИЕ: Это решение для целых чисел, поскольку в исходном вопросе представлен только целочисленный регистр.

Сначала выясните, сколько элементов включено в интервал

dCon = diff(conditions,[],2)+1;

Затем создайте возрастающую последовательность индексов для максимального количества элементов (этот список был бы огромен для случая с плавающей запятой, и, таким образом, это решение, практически / эффективно, не распространяется на числа с плавающей запятой)

idx0 = repmat(1:max(dCon),length(dCon),1);

Ограничьте слишком большие индексы

idx0(idx0>dCon)=1;

Теперь добавьте начальную точку

idx = idx0 + conditions(:,1)-1;

Теперь idx содержит все числа, которые вы хотите изменить.Используйте ismember, чтобы найти все элементы в main и изменить их на 1.

main(ismember(main(:,1),idx(:)),2)=1;

РЕДАКТИРОВАТЬ: Это полный пример с вектором из Gnovice в комментариях

main = zeros(10, 2);
main(:, 1) = [1; 2; 2; 2; 3; 3; 4; 6; 6; 8];
conditions = [2, 3; 6, 8]
dCon = diff(conditions,[],2)+1;
idx0 = repmat(1:max(dCon),length(dCon),1);
idx0(idx0>dCon)=1;
idx = idx0 + conditions(:,1)-1;
main(ismember(main(:,1),idx(:)),2)=1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...