Reputation: 201
I'm working with a large vector which contains the values of a linear combination of multiple sine functions (where the first entry is at a time of 0 miliseconds and the nth entry is at the nth miliseconds). Now I want to extract the pieces of the vector which contain (the same combination of ) sine functions, and store them separately.
Hence I want to check whether 5 entries next to each other equal zero, which means this would be a 'cut' between two separate linear combinations. If there are 5 or more entries next to each other which equal zero, the this is where the cut should be made. As an example the following (short) vector.
Let vector = [ 0 0 0 0 0 0 0 8 9 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ]
which should be cut into two separate vectors, namely
vec1= [8 9 1 0 0 3 2]
and vec2= [6 6 2 0 0 0 1]
.
I think I could use the built-in find
function but I don't think it can look for 'at least' 5 entries next to each other which equal 0, correct?
Upvotes: 0
Views: 85
Reputation: 10792
You can use regexp
with the split
option:
v = [0 0 0 0 0 0 0 8 90 0 0 0 0 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ];
% vector to string then extract the subvector
r = regexp(num2str(v),'(?<![0-9])(0\s+){5,}','split')
% string to vector
out = cellfun(@str2num,r,'UniformOutput',0)
With this regular expression: (?<![1-9])(0\s+){5,}
(?<![0-9])
: check that a zero is not preceded by a digit, so 90 0 0 0 0
should not split the vector.
(0\s+){5,}
: check for, at least, 5 consecutive 0.
Upvotes: 1
Reputation: 30046
Starting with your example...
v = [ 0 0 0 0 0 0 0 8 9 1 0 0 3 2 0 0 0 0 0 6 6 2 0 0 0 1 ];
We could do the following:
% 1. Create an index `idx` which groups elements either as zeros or non-zeros,
% with an increasing group number for each subsequent set
idx = cumsum( [1, diff(v==0) ~= 0] );
% = [ 1 1 1 1 1 1 1 2 2 2 3 3 4 4 5 5 5 5 5 6 6 6 7 7 7 8 ];
% 2. Split by this group, regardless of what's in it
grps = splitapply( @(x){x}, v, idx );
% = { {1×7 double}, {1×3 double}, {1×2 double}, {1×2 double}, {1×5 double}, ... }
% 3. Get the indices for groups, incremented when the 5-zeros condition is met
zIdx = cellfun( @(x) x(1) == 0, grps ); % Just alternating 0/1, as groups alternate
idx = cellfun( @numel, grps ) >= 5 & zIdx;
idx = cumsum( idx ) .* ~idx;
% = [ 0 1 1 1 0 2 2 2 ]
% 4. Group everything together
out = arrayfun( @(x) [grps{idx==x}], 1:max(idx), 'uni', 0 );
% { [8 9 1 0 0 3 2], [6 6 2 0 0 0 1] }
I'm not sure this is any quicker than just writing a loop...
Upvotes: 2