Reputation: 2544
I want to change the value in column 2 based on the values in column 1 in one array (main
), using a start and end index from another array (conditions
).
In conditions
column 1 holds the start index, column 2 the end index.
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
I know how to do it using a loop (shown below), but am looking for a faster method.
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
Doing main(main(:, 1) >= conditions(:, 1) & main(:, 1) <= conditions(:, 2), 2) = 1
results in the error Matrix dimensions must agree
.
Is there a non-loop method?
Upvotes: 1
Views: 156
Reputation: 3052
NOTE: This is a solution for integers only as the original question only presented the integer case.
First, figure out how many elements there are included in the interval
dCon = diff(conditions,[],2)+1;
Then construct an increasing sequence of indexes to the maximum number of elements (this list would be enormous for the float case, and thus this solution does not, feasibly/efficiently, extend to floats)
idx0 = repmat(1:max(dCon),length(dCon),1);
Cap off the indexes that are too large
idx0(idx0>dCon)=1;
Now add the starting point
idx = idx0 + conditions(:,1)-1;
now idx
contains all the numbers you want to change. Use ismember
to find all elements in main
and change them to 1
.
main(ismember(main(:,1),idx(:)),2)=1;
EDIT: This is the full example with the vector from Gnovice in the comments
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;
Upvotes: 3
Reputation: 60474
Your attempt is almost correct. If you transpose the conditions
, then you'll be comparing a column of main
with a row of conditions
, leading to MATLAB doing implicit singleton expansion, giving a matrix output. This matrix can then be collapsed using 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;
(I've separated out the code into 3 lines for clarity, but of course they can all be a single line.)
Note that for versions of MATLAB prior to R2016b, this code won't work, you'll need to use bsxfun
instead:
index = bsxfun(@ge,main(:,1),conditions(:, 1).') & bsxfun(@le,main(:, 1),conditions(:, 2).');
Upvotes: 3