3
votes

I have a vector that I know will consist of the values 100, 200 and 400. The values will not be mixed up but be it order, for example

target = [100 100 100 100 200 200 400 400 400];

I want to split this vector up into three vectors, each vector containing all the values of that kind.

A = [100 100 100 100];
B = [200 200];
C = [400 400 400];

The length of target will change from time to time and so will the proportion of 100, 200 and 400.

How can I make this split in an easy way?

My own solution looks like this but I was thinking that there is 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
4

4 Answers

3
votes

Something simpler:

target=[100 100 100 100 200 200 400 400 400];

A = target(target==100)
B = target(target==200)
C = target(target==400)

How this works: target==x returns a logical array of size equal to target. Then you can use that logical array to index target.

3
votes

A little more generic 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 would be:

%// 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 personally would recommend you to 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 generic and error prone approach I could think of, would be:

%// create a map container with all values you're expecting and it's 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 struct out with the fields A, B and C:

The interesting part is, that you could also generate the keySet and valueSet automatically:

%// 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 which are your elements and how many different ones you actually have. The only difference to your original request is that you don't get the variables A, B and C but out.A, out.B and out.C

enter image description here

2
votes

Here is a way 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 looks like this:

DiffVector =

  -Inf     0     0     0   100     0   200     0     0   Inf


%// Find where values are not equal to 0. That's the starting indices of
%each sequence of numbers of interest.
indices = find(DiffVector~=0)

indices looks like this:

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 content of the 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 only one for simplicity.

Yay!

1
votes

Yet another way: sort and then split into cells using mat2cell:

st = sort(target);
result = mat2cell(st, 1, diff([0 find(diff(st)) numel(st)]));