pradeep kumar Tarei
pradeep kumar Tarei

Reputation: 83

Indexing rows of a table by comparing the values between two cells

enter image description here

I have a table like the above attachment. Column A and Column B contains some elements in terms of cell array. I want to create the third column (Level) as the resultant column; based on the following logic.

  1. The row for which, value of cell A = value of cell B will be labeled1. (In the 3rd row, the value of column A=value of column B= 3, hence labeled 1).

  2. Next, the preceding value will be removed from all the cells of column A; and the step 1 will be repeated until all the rows are labeled. (In the second step, 3 will be removed from all the cells, hence both row 1 and row 2 will be labeled as 2;In the final step, elements {1,2} will be further removed from the last row resulting the level as 3 )

I am using cell2mat and setdiff functions to compare the values across the cells, but I am not able to frame the above 2 logical steps to run my code successfully. I have just started learning MATLAB, Any help will be highly appreciated.

Upvotes: 4

Views: 210

Answers (2)

gnovice
gnovice

Reputation: 125854

Here's the simplest answer I could come up with, using a single while loop and assuming the cells of A and B contain row vectors:

Level = zeros(size(A));
index = cellfun(@isequal, A, B);
while any(index)
  Level(index) = max(Level)+1;      
  A = cellfun(@(c) {setdiff(c, unique([A{index}]))}, A);
  index = cellfun(@isequal, A, B);
end

The above code first initializes a matrix of zeroes Level the same size as A to store the level values. Then it finds a logical index index of where there are matching cell contents between A and B using cellfun and isequal. It will continue to loop as long as there are any matches indicated by index. The corresponding indices in Level are set to the current maximum value in Level plus one. All the matching cell contents from A are concatenated and the unique values found by unique([A{index}]). A set difference operation is then used (along with cellfun) to remove the matching values from each cell in A, overwriting A with the remaining values. A new index for matches is then computed and the loop restarts.

Given the following sample data from your question:

A = {[1 2 3]; [2 3]; 3; [1 2 3 4]};
B = {[1 2]; 2; 3; 4};

The code returns the expected level vector:

Level =

     2
     2
     1
     3

Upvotes: 2

Leander Moesinger
Leander Moesinger

Reputation: 2462

Not my best work, i think it is possible to get rid of the inner loop.

% your testdata
A = {[1 2 3]
    [2 3]
    3
    [1,2,4]};
B = {[1 2]
    2
    3
    4};


Level = NaN(numel(B),1);
temp = A; % copy of A that we are going to remove elements from
k = 0; % loop couter
while any(isnan(Level)) % do until each element of Level is not NaN
    k = k+1; % increment counter by 1

    % step 1
    idx = find(cellfun(@isequal,temp,B)); % determine which cells are equal
    Level(idx) = k; % set level of equal cells

    % step 2
    for k = 1:numel(idx) % for each cell that is equal
        %remove values in B from A for each equal cell
        temp = cellfun(@setdiff,temp,repmat(B(idx(k)),numel(B),1),'UniformOutput',0);
    end   
end

Upvotes: 1

Related Questions