Reputation: 11
I have a vector that looks like this:
A = [1 7 3 4 0 0 0 0 0 0 1 4 5 3 2 4 0 0 0 0 0 0 0 2 4 3 10 3 5 3 2 1]
I would like the vector to look like this:
1 7 3 4
1 4 5 3 2 4
2 4 3 10 3 5 3 2 1
I am trying to delete the zeroes out of the vector and, when there is a zero, replace the preceding number after into a new column and continue through the length of the vector. I am currently using the command L = A(A~=0)
to delete the zeroes, but get stuck there.
Upvotes: 1
Views: 49
Reputation: 112679
Here's a way to do it without loops:
A = [1 7 3 4 0 0 0 0 0 0 1 4 5 3 2 4 0 0 0 0 0 0 0 2 4 3 10 3 5 3 2 1]; %// data
nz = logical(A); %// logical index of nonzeros of A
ind = find(conv(2*([false nz])-1,[1 -1],'valid')==2); %// find ends of runs of zeros
B = zeros(size(A)); B(ind) = 1; B = cumsum(B); %// integer label for each group
result = accumarray(B(nz).', A(nz).', [], @(x){x.'}); %'// nonzero elements by group
The result is a cell array of row vectors. In your example,
>> celldisp(result)
result{1} =
1 7 3 4
result{2} =
1 4 5 3 2 4
result{3} =
2 4 3 10 3 5 3 2 1
Upvotes: 1
Reputation: 5823
If you want the result to be a matrix.. you can't. Matrices cannot have empty elements as you show. The best you can do is a cell array, where each element of the cell corresponds to a row in the "matrix".
First, we can find all the locations where there isn't a zero:
>> nonZeroIndices = find(A)
nonZeroIndices =
1 2 3 4 11 12 13 14 15 16 24 25 26 27 28 29 30 31 32
It should be obvious that "runs" of indices corresponds to where there are non-zeroes in A
. That is to say, the difference between some index n
and n-1
is 1. Let's use diff
to find the delineations:
>> diff(nonZeroIndices)
ans = 1 1 1 7 1 1 1 1 1 8 1 1 1 1 1 1 1 1
The non-one values correspond to where those "breaks" in the runs occur. Let's find those indices..
>> breakIndices = find(diff(nonZeroIndices) > 1)
breakIndices =
4 10
So A(nonZeroIndices(1:4))
, A(nonZeroIndices(5:10))
, and A(nonZeroIndices(11:end))
correspond to the 3 "rows" we want. Note that each of these indices corresponds to the end of the run, so I'll prepend a 0 to it to make a for
loop easier to work with.
Here is my final solution:
nonZeroIndices = find(A);
breakIndices = [0 find(diff(nonZeroIndices) > 1)];
for ii = 1:numel(breakIndices)
if ii ~= numel(breakIndices)
c{ii,:} = A(nonZeroIndices(breakIndices(ii)+1) : nonZeroIndices(breakIndices(ii+1)));
else
c{ii} = A(nonZeroIndices(breakIndices(ii)+1):end);
end
disp(c{ii})
end
Running this, you get the required output:
1 7 3 4
1 4 5 3 2 4
2 4 3 10 3 5 3 2 1
Upvotes: 1
Reputation: 15349
Your desired output seems to not be a vector, but rather three separate vectors. I'm going to assume you want them as separate cells (c{1}
, c{2}
and c{3}
) of a cell array c
:
A = [1 7 3 4 0 0 0 0 0 0 1 4 5 3 2 4 0 0 0 0 0 0 0 2 4 3 10 3 5 3 2 1];
z = diff([0 A 0] == 0);
firstnonzero = find(z < 0);
lastnonzero = find(z > 0) - 1;
c = {};
for i = 1:numel(firstnonzero)
c{i} = A(firstnonzero(i):lastnonzero(i));
end
disp(c)
Upvotes: 0