select elements of matrix from indices defined in an array

Say I have a 4x3 matrix of non-zero elements (A):
A = (0.1299 0.3371 0.5285
0.5688 0.1622 0.1656
0.4694 0.7943 0.6020
0.0119 0.3112 0.2630)
and two 1x3 arrays B and C such as:
B = (1 2 4)
C = (2 3 4)
I would like to build a matrix D that selects rows 1 to 5 from column 1, 2 to 3 from column 2 and row 4 from column 3...
D = (0.1299 0 0
0.5688 0.1622 0
0 0.7943 0.6020
0 0 0)
I am using a for loop to do it which is quite inefficient.. Any suggestions? Thanks!

댓글 수: 2

"for loop to do it which is quite inefficient" Are you sure?
Jan
Jan 2017년 8월 12일
편집: Jan 2017년 8월 12일
You mean: "Rows 1 to 2 from column 1."
In the example you have chosen the 3. row of column 3, not the 4th one.
It is a good strategy to post the data in valid Matlab syntax to allow for an easy using to test the suggested solutions: It is not much work to replace the parenthesis by square brackets for valid Matlab matrices. But if you do this, it has to be done once only.
Please check your question before posting. It is not efficient, if the readers guess the details.
If you post your code, we could see the problem of the loop method.

댓글을 달려면 로그인하십시오.

 채택된 답변

Jan
Jan 2017년 8월 12일
편집: Jan 2017년 8월 12일
Nope, a loop is efficient here:
A = [0.1299 0.3371 0.5285; ...
0.5688 0.1622 0.1656; ...
0.4694 0.7943 0.6020; ...
0.0119 0.3112 0.2630];
B = [1 2 4];
C = [2 3 4];
D = zeros(size(A));
for k = 1:numel(B)
D(B(k):C(k), k) = A(B(k):C(k), k);
end
A vectorized version:
[s1, s2] = size(A);
sp = [s1 + 1, s2];
M = zeros(sp);
M(sub2ind(sp, B, 1:s2)) = 1;
M(sub2ind(sp, C + 1, 1:s2)) = -1;
M = cumsum(M(1:s1, :), 1);
D = A .* M;
Some timings (R2016b, Win7/64, Core2Duo):
A = rand(1000, 1000);
BB = randi(1000, 1, 1000);
CC = randi(1000, 1, 1000);
B = min(BB, CC);
C = max(BB, CC);
tic; for q = 1:100; D = fcn(A, B, C); end, toc
Elapsed time is 1.052819 seconds. % Loop
Elapsed time is 2.604761 seconds. % Vectorized
The creation of the index matrix M and the multiplication A .* M is expensive, but the copy of memory blocks in the loop method is cheap.
Note: The indexing in D(B(k):C(k), k) is very efficient, because Matlab does not create the vector B(k):C(k) explicitly. This saves temporary memory and reduce the number of out-of-range checks, because only the first and the last element are checked. In opposite to this, the [ ] operator does create the temporary index vectors:
for k = 1:numel(B)
D([B(k):C(k)], k) = A([B(k):C(k)], k);
end
% Elapsed time is 1.634790 seconds.
or
for k = 1:numel(B)
v = B(k):C(k);
D(v, k) = A(v, k);
end
% Elapsed time is 1.458995 seconds.
Avoid the use of unnecessary square brackets.

댓글 수: 1

Thanks! I was negatively biased against the 'for loop'.. I assumed that a vectorized solution will always be more efficient and I was wrong.
PS. Sorry for the typos and for forgetting about inserting the code I had :(.

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

도움말 센터File Exchange에서 Multidimensional Arrays에 대해 자세히 알아보기

질문:

2017년 8월 11일

댓글:

2017년 8월 12일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by