0
votes

Using matlab, I am attempting to move rows from one matrix (RF) to a cell array using equivalent values in the matrix and the array. For each value i in the first column of matrix RF I would like to find which cell contains the same value. I would then like to move the row containing i (i,:) to the first row of zeros in that cell. At the end I will delete all remaining rows of zeros in M.

I currently have the following code:

RF = [1 7; 4 8; 3 9; 7 10]
M = cell(3,1);
for k = 1:3
    M{k} = zeros(10,2);
end 
matsize2 = length((RF(:)));
halfmatsize2 = 0.5 * matsize2;
for i = 1:halfmatsize2   % Values in the first column of RF
    J = RF(i);
    JK = RF(i,:);
    L = find(cell2mat(M)==J); % I wanted this line to give me the index of the cell containing J
    H = find(M{L}==0, 1, 'first'); % This returns an error
    M{L}(H,:)= JK; % Puts JK into the first row of zeros (my goal)
end

This outputs the error "index exceeds matrix dimensions" for the line H = find(M{L}==0, 1, 'first'); This is because while I wanted L to return the index of the cell containing J, it is giving me the location with all cells combined into one. What's the best way to find the cell containing J and then move JK to the first row of zeros in the aforementioned cell?

For example, I have the matrix RF = [1 7; 4 8; 3 9; 7 10] and the cell array M = cell(3,1), where M{1}=[1 4; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0], M{2} = [2 5; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0] and M{3} = [3 6; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0; 0 0].

I would like to end with M{1} = [1 4; 1 7; 4 8; 7 10], M{2} = [2 5] and M{3} = [3 6; 3 9].`

The overarching goal here is to automate the process for taking a matrix containing parent-offspring relationships for species and turn it into a phylogeny. The example provided is the simple one I've been using to test other aspects of the larger code.

Help would be much appreciated! After hours of Google searching and trial/error I remain stuck. I would also appreciate advice on how to streamline my rather clumsy code.

Thanks in advance!

1

1 Answers

2
votes

Based on what I have understood, I think this would work for you and should be more efficient too -

%// Get matches between each element of col1 of RF against each in its col2
RF12 = bsxfun(@eq,RF(:,1),RF(:,2)');   %//'

%// Cut each cell of M into cells that have only non-zero rows 
M_cut = arrayfun(@(n) M{n}(any(M{n},2),:),1:numel(M),'Uni',0)

M_out = cell(size(M)); %// storage for output
for n = 1:numel(M) %// we need to iterate through each cell

    %// Matches for all elements in col1 of RF against all elements in M
    M_RF1 = any(bsxfun(@eq,M{n}(:),RF(:,1)'));  %//'

    %// Matching row indices for all elements in col1 of RF against all
    %// matches in its col2 and all elements in M
    idx = any(bsxfun(@and,RF12,M_RF1),2) | M_RF1(:);  %//'

    %// Logically index into RF for the matches and vertically concatenate
    %// with the M_cut cells to give us the desired output in each cell
    M_out{n} = [M_cut{n} ; RF(idx,:)];
end
celldisp(M_out) %// display output

Output -

M_out{1} =
     1     4
     1     7
     4     8
     7    10
M_out{2} =
     2     5
M_out{3} =
     3     6
     3     9