简体   繁体   中英

MATLAB - Avoid repeated values in a vector inside cell arrays and take next

This is the problem:

I have a cell array on the form indx{ii} where each ii is an array of size 1xNii (this means the arrays have different size). And another cell array on the form indy{jj} where each jj is an array of the same size as ii .

The question is that I would like to create a function evaluates the values in the arrays of indx{:} and take the first one that is not repeated, and if is a repeated value then take the next.

I will try to explain with an example. Suppose we have indx and indy that are the cell arrays:

indx{1} = [1 3 2 7];
indx{2} = [3 8 5];
indx{3} = [3 6 2 9];
indx{4} = [1 3 4];
indx{5} = [3 1 4];

indy{1} = [0.12 0.21 0.31 0.44];
indy{2} = [0.22 0.34 0.54];
indy{3} = [0.13 0.23 0.36 0.41];
indy{4} = [0.12 0.16 0.22];
indy{5} = [0.14 0.19 0.26]; 

What I want the code to do is take the first value and is not repeated in indx and the equivalent in indy . So the answer for the example should be:

ans=

indx{1} = 1;
indx{2} = 3;
indx{3} = 6;
indx{4} = 4;
indx{5} = [];

indy{1} = 0.12;
indy{2} = 0.22;
indy{3} = 0.23;
indy{4} = 0.22;
indy{5} = [];

In ans , for indx{1} the code takes 1 because is the first and it's not repeated and takes the equivalent value in indy . Then for indx{2} it takes 3 because is the first value and is not repeated as first value in any array before. But for ind{3} it takes 6 , because the first value that is 3 is repeated, and takes the equivalent value to 6 in indy which is 0.23 . For ind{4} the first and second value they are already repeated as first values so the code takes 4 and its equivalent in indy . And last, for indx{5} since all values are already repeated the code should take no value.

indx{1} = [1 3 2 7];
indx{2} = [3 8 5];
indx{3} = [3 6 2 9];
indx{4} = [1 3 4];
indx{5} = [3 1 4];

indy{1} = [0.12 0.21 0.31 0.44];
indy{2} = [0.22 0.34 0.54];
indy{3} = [0.13 0.23 0.36 0.41];
indy{4} = [0.12 0.16 0.22];
indy{5} = [0.14 0.19 0.26]; 

indx2 = NaN(numel(indx),1);
indx2(1) = indx{1}(1);
indy2 = NaN(numel(indy),1);
indy2(1) = indy{1}(1);
for ii = 2:numel(indx)
    tmp1 = indx{ii}'; % get the original as array
    tmp2 = indy{ii}';
    if numel(tmp1)>numel(indx2)
        tmp3 = [indx2;NaN(numel(tmp1)-numel(indx2),1)];
        tmp4 = [indx2;NaN(numel(tmp1)-numel(indx2),1)];
    else
        tmp1 = [tmp1;NaN(numel(indx2)-numel(tmp1),1)];
        tmp2 = [tmp2;NaN(numel(indx2)-numel(tmp2),1)];
        tmp3 = indx2;
        tmp4 = indy2;
    end
    tmp5 = ~ismember(tmp1,tmp3); % find first non equal one
    tmp6 = find(tmp5,1,'first');
    indx2(ii) = tmp1(tmp6); % save values
    indy2(ii) = tmp2(tmp6);
end
N = numel(indx2);
indx2 = mat2cell(indx2, repmat(1,N,1));
N = numel(indy2);
indy2 = mat2cell(indy2, repmat(1,N,1));

indx2 =

    [  1]
    [  3]
    [  6]
    [  4]
    [NaN]

What I have done here is to first initialise your output cells to have the same number of cells as your original data. Then I assign value 1, since that one will always be unique, it is the first entry. After that I use a for loop to first convert all four cell arrays (2 input, two output) to regular arrays for processing with ismember , where I check for the all non-equal number between the next input cell and the existing numbers in your output. Then find is employed to get the first non-matching number. Lastly, the numbers are assigned to the arrays if present.

As a comment on the usage of booleans with NaN , try NaN ~=NaN and NaN ==NaN . The first will give you 1, whilst the second will give you zero. This quality makes NaNs the ideal choice of filler here, because 0 == 0 will result in 1:

A = [1,2,5,4,NaN];
B = [1,3,7,NaN,NaN];
ismember(A,B)
=

     1     0     0     0     0

Thus the NaNs do not equal one another and will therefore not pollute your solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM