Change a value after a maximum five-consecutive column of zero

I have a matrix [3000,1000] which has only 0, 1, and -1. If there is a -1 in a row followed by a (maximum) consecutive five-columns of zeros then followed by 1, this 1 value should change to 2.
I am looking for the fastest way to do it in Matlab. Is there anyway without a loop? if not, what is the best way?
For example
A = [1 0 0 -1 0 0 0 0 1 0 0 -1 0 0 1;
0 -1 0 0 0 0 0 0 1 -1 0 1 0 0 -1];
% I would like to change matrix A as follow
A = [1 0 0 -1 0 0 0 0 2 0 0 -1 0 0 2;
0 -1 0 0 0 0 0 0 1 -1 0 2 0 0 -1 ];
Thanks in advance,

3 Comments

Why is the output not:
A = [1 0 0 -1 0 0 0 0 2 0 0 -1 0 0 2;
0 -1 0 0 0 0 0 2 -1 0 2 0 0 -1 0];
^
There is a -1 at A(2, 2), 5 consecutive zeros and then a 1. A(2,8) should be a 2 in consequence.
Please post the relevant sizes. It matters if you have a [1e6, 10] or [10 x 1e6] array.
Sorry, it was my mistake. I edit the example so that there are 6 consecutive zeros now before 1
@Jan, the matrix size is [3000,1000]. Thank you

Sign in to comment.

 Accepted Answer

I don't think this can be done more efficiently than with a loop over the rows:
for row = 1:size(A, 1)
col = find(A(row, :));
tochange = diff(col) <= 5 & A(row, col(1:end-1)) == -1 & A(row, col(2:end)) == 1;
A(row, col([false, tochange])) = 2;
end

4 Comments

Thank you! It works like a charm!
I tried to find a reason for using a "false" function
A(row, col([false, tochange])) = 2;
But I still couldn't find it. Could you please elaborate more the logic behind it?
Thank you
The result of diff is a vector with one less element than col. tochange(1) actually corresponds to col(2|, so I just prepend false to vector (since the 1st element is never going to have to be changed anyway).
Thank you for your explanation

Sign in to comment.

More Answers (2)

A = [1 0 0 -1 0 0 0 0 1 0 0 -1 0 0 1; ...
0 -1 0 0 0 0 0 1 -1 0 1 0 0 1 0];
[s1, s2] = size(A);
Av = reshape(A.', 1, []); % Convert it to 1 vector
for k = 0:5
index = strfind(Av, [-1, zeros(1, k), 1]);
index = index(mod(index, s2) < s2 - k); % Omit matches at end of row
Av(index + k + 1) = 2;
end
B = reshape(Av, s2, []).';
This is an approach to modify an identify an arbitrary pattern and modify a value, Using for loop and comparing them by converting them to char array.
A = [1 0 0 -1 0 0 0 0 1 0 0 -1 0 0 1;
0 -1 0 0 0 0 0 1 -1 0 1 0 0 1 0];
pattern = [-1 0 0 0 0 1];
strA = num2str(A+1); % +1 is added to remove negative signs for easy manipulation as strings
strPattern = strrep(num2str(pattern+1), ' ', '');
for i=1:size(A,1)
index = strfind( strrep(strA(i,:), ' ', ''), strPattern) + length(pattern) -1;
if ~isempty(index)
A(i, index) = 2;
end
end

2 Comments

Note that you don't need to convert numbers to char to use strfind. Despite not being actually documented, strfind works just as well for detecting patterns of numbers
strfind(A(i, :), [-1 0 0 0 0 0 1])
The problem here is that several patterns are acceptable, [-1 1], [-1 0 1], ..., [-1 0 0 0 0 0 1], so a pattern search is not particularly useful. I guess a regexp would work (which does requires a conversion to char) but I'm not convinced the extra complexity and time taken by the regex would be better than the simple for loop I've detailed.
Thank you Ameer for your answer. As Guillaume mentioned above, there are several patterns that acceptable here.

Sign in to comment.

Categories

Community Treasure Hunt

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

Start Hunting!