How to group values in a vector based on certain condition?

I have a row vector that has values 1 to 5 that keeps repeating like a cycle as following.
row = [1; 2; 3; 4; 5; 1; 1; 2; 3; 4; 5; 5; 1; 1; 2; 2; 3; 4; 5; 5]
I need to group this data taking 1 and 5 as reference. If the 1 or 5 is occuring more than once consecutively, consider the first 1 and last 5.
Ans =
[1 2 3 4 5 0 0 0;
1 1 2 3 4 5 5 0;
1 1 2 2 3 4 5 5 ]
Any ideas?
Thanks

 Accepted Answer

If the sub-sequence always starts with a 1 and ends with a 5, you could do this:
row = [1; 2; 3; 4; 5; 1; 1; 2; 3; 4; 5; 5; 1; 1; 2; 2; 3; 4; 5; 5];
start_val = 1;
end_val = 5;
cycle_end_idx = [0; find(diff(row) == start_val-end_val); numel(row)]
cycle_end_idx = 4×1
0 5 12 20
n_cycles = numel(cycle_end_idx)-1;
cycle_length = diff(cycle_end_idx);
M = zeros(n_cycles,max(cycle_length));
for ii = 1:n_cycles
M(ii,1:cycle_length(ii)) = row(cycle_end_idx(ii)+1:cycle_end_idx(ii+1));
end
disp(M);
1 2 3 4 5 0 0 0 1 1 2 3 4 5 5 0 1 1 2 2 3 4 5 5
Ultimately, however, you may find that it's better to store those sub-sequences in a cell array rather than a matrix with extra zeros:
C = cell(1,n_cycles);
for ii = 1:n_cycles
C{ii} = row(cycle_end_idx(ii)+1:cycle_end_idx(ii+1)).';
end
format compact
celldisp(C);
C{1} = 1 2 3 4 5 C{2} = 1 1 2 3 4 5 5 C{3} = 1 1 2 2 3 4 5 5

6 Comments

Thanks.
What change i can do to the above code if the starting value for the sub-sequences is not always 1 but 2 in some cases and the ending is fixed at 5?
row = [1; 2; 3; 4; 5; 2; 3; 4; 5; 5; 2; 2; 3; 4; 5; 5];
Here's one way:
row = [1; 2; 3; 4; 5; 2; 3; 4; 5; 5; 2; 2; 3; 4; 5; 5];
start_val = 2;
end_val = 5;
cycle_end_idx = [0; find(diff(row) <= start_val-end_val); numel(row)];
n_cycles = numel(cycle_end_idx)-1;
cycle_length = diff(cycle_end_idx);
M = zeros(n_cycles,max(cycle_length));
for ii = 1:n_cycles
M(ii,1:cycle_length(ii)) = row(cycle_end_idx(ii)+1:cycle_end_idx(ii+1));
end
disp(M);
1 2 3 4 5 0 2 3 4 5 5 0 2 2 3 4 5 5
And here's a more general method that handles any sequence of non-decreasing cycles like these - so that you can detect the end of a cycle by seeing where the difference between an element and the previous element is negative. (The only difference between the three methods I've shown is how cycle_end_idx is defined.)
row = [1; 2; 3; 4; 5; 2; 3; 4; 5; 5; 4; 5; 6; 7];
cycle_end_idx = [0; find(diff(row) < 0); numel(row)];
n_cycles = numel(cycle_end_idx)-1;
cycle_length = diff(cycle_end_idx);
M = zeros(n_cycles,max(cycle_length));
for ii = 1:n_cycles
M(ii,1:cycle_length(ii)) = row(cycle_end_idx(ii)+1:cycle_end_idx(ii+1));
end
disp(M);
1 2 3 4 5 2 3 4 5 5 4 5 6 7 0
Very Helpful. Thanks a lot.
Assuming its a sequence of non decreasing cycle starting from 0 and ending with 5,
but each cycle has different length...like the following:
row = [0;1;1;2;2;3;4;5;0;1;2;3;4;5;5;0;1;1;2;4;5;0;1;2;3;4;5]
after executing the above code, the output will be,
M =
0 1 1 2 2 3 4 5
0 1 2 3 4 5 5 0
0 1 1 2 4 5 0 0
0 1 2 3 4 5 0 0
But, Instead of padding the last missing column with zeros, how can i expand or shrink the cycle to my desired number of samples (for eg: 6) per cycle, so that i always have six columns no matter how big or small the cycle length is.
Thanks.
What should be the output for row = [0;1;1;2;2;3;4;5;0;1;2;3;4;5;5;0;1;1;2;4;5;0;1;2;3;4;5] with imposed cycle length (i.e., desired number of columns in output matrix) of 5?

Sign in to comment.

More Answers (0)

Categories

Find more on MATLAB in Help Center and File Exchange

Products

Release

R2020a

Asked:

on 27 Mar 2022

Commented:

on 2 May 2022

Community Treasure Hunt

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

Start Hunting!