Split vector into multiple vectors based on its content
I have a vector that I know will consist of the values ββ100, 200 and 400. The values ββwill not be jumbled, but let it be in order, for example
target = [100 100 100 100 200 200 400 400 400];
I want to split this vector into three vectors, each vector contains all values ββof this type.
A = [100 100 100 100];
B = [200 200];
C = [400 400 400];
The target duration will change from time to time, as well as the proportion of 100, 200 and 400.
How can I make this split in a simple way?
My own solution looks like this, but I thought there was another way that requires less code.
columns = size(target, 2);
A = [];
B = [];
C = [];
% Splitting target into groups
for j = 1:columns
if target(1, j) == 100
A = [A, 100];
elseif target(1, j) == 200
B = [B, 200];
elseif target(1,j) == 400
C = [C, 400];
end
end
source to share
A slightly more general approach:
%// find and count unique elements
[a,b] = hist(target,unique(target));
%// Create vectors according to target and number occurences and store them in cell array
temp = arrayfun(@(x,y) y*ones(x,1),a,b,'uni',0)
an alternative and probably faster approach:
%// get indices of unique values
[~,~,c] = unique(target)
%// Create vectors according to indices and store them in cell array
temp = accumarray(c(:),target(:),[],@(x) {x})
I would personally recommend that you stop at this point and continue with the cell array!
If you know how many unique elements there are, and you really want to store them in separate variables, you can use:
[A,B,C] = temp{:}
The most common and error prone approach I could think of would be:
%// create a map container with all values you're expecting and it corresponding specifier
valueSet = {'A', 'B', 'C'};
keySet = [100 200 400];
mapObj = containers.Map(keySet,valueSet)
%// create a struct and distribute keys to specifier
for ii = 1:numel(keySet);
out.(mapObj(keySet(ii))) = target(target == keySet(ii));
end
You get a structure out
with fields A
, B
and C
:
The interesting part is that you can also automatically generate keySet
and valueSet
:
%// keySet are all unique values of target
keySet = unique(target)
%// create specifiers according to number of unique elements
valueSet = cellstr(char(65:65+numel(keySet)-1).') %'
%// you get 'A' 'B' and 'C' to use as field names
This way you don't need to know what your elements are and how many different ones you have. The only difference from your original request is that you don't get the variables A
, B
and C
, a out.A
, out.B
andout.C
source to share
Here's how to do it using diff
and find
.
clear clc close all target=[100 100 100 100 200 200 400 400 400]; %// Form vector containing cumulative differences from consecutive elements DiffVector = [-Inf diff([target Inf])];
DiffVector
as follows:
DiffVector =
-Inf 0 0 0 100 0 200 0 0 Inf
%// Find where values are not equal to 0. That the starting indices of
%each sequence of numbers of interest.
indices = find(DiffVector~=0)
indices
as follows:
indices =
1 5 7 10
%// Put every sequence in its own cell.
v = cell(1,numel(indices)-1);
for k = 1:numel(indices)-1
v{k} = target(indices(k):idx(k+1)-1);
end
Display the contents of a cell array
celldisp(v)
v{1} =
100 100 100 100
v{2} =
200 200
v{3} =
400 400 400
You can combine the first 2 steps into one just for simplicity.
Yay!
source to share