I have this cells array which is came from a mat lab code that generates dewey IDs:
POT1 =
'a0' [] [] []
'a0' 'c0' [] []
'a0' 'b0' [] []
'a0' 'c1' [] []
'a0' 'd0' [] []
'a0' 'c0' 'd1' []
'a0' 'b0' 'd2' []
'a0' 'd0' 'd3' []
'a0' 'd0' 'c2' []
'a0' 'd0' 'b1' []
'a0' 'd0' 'd4' []
'a0' 'c1' 'c3' []
'a0' 'c1' 'b2' []
'a0' 'c1' 'c3' 'd5'
'a0' 'c1' 'b2' 'd6'
'a0' 'd0' 'b1' 'd7'
'a0' 'd0' 'c2' 'd8'
note that column 1 is parent of column 2 and column 2 is paret of column 3..etc
so I want to build a code that gives the full name of each cell as follow:
POT1 =
a0 [] [] []
a0 a0.c0 [] []
a0 a0.b0 [] []
a0 a0.c1 [] []
a0 a0.d0 [] []
a0 a0.c0 a0.c0.d1 []
a0 a0.b0 a0.b0.d2 []
a0 a0.d0 a0.d0.d3 []
a0 a0.d0 a0.d0.c2 []
a0 a0.d0 a0.d0.b1 []
.
.
.
.
The code which I build is not complete and gives me :" Index exceeds matrix dimensions" error :
for i=1:length(POT1)
for j=3:size(POT1,2)
if ~isempty(POT1{i,j})
POT1{i,j}=[POT1{i,j-2} POT1{i,j-1} POT1{i,j}];
end
end
end
POT1
I think you're on the right track, but it's easier if you process it column by column. This way, you just have to look one column back for each entry:
for jj=2:size(POT1,2)
for ii=1:size(POT1,1)
if ~isempty(POT1{ii,jj})
POT1{ii,jj}=[POT1{ii,jj-1} '.' POT1{ii,jj}];
end
end
end
btw: length returns the Length of vector or largest array dimension, so next time, better use size.
If you have vectors with ' %Two spaces ' on the empty spaces it will be really easy.
You can just transform it into a matrix and the rest is simple as this:
[POT1(:,1:2) '.' POT1(:,3:4)]
Afterwards you can just strip the spaces and done.
Related
I have a set of data in a cell array ,a part of which is shown below.The first three columns of row 2 and row 3 are same.In the 2nd row from columns 4 onwards it contains P0702 which is already captured in row 3(with the same first three columns as row 2).So i would like the delete the 2nd row.Similarly 5 and 6th rows have same data in the first three columns.P0882 and P0702 in the fifth row is also present in the sixth row,so i would want to delete the 5th row .
Data before duplicates
'1FA' 2 'Fm' [] [] [] [] [] [] [] 'P2700' []
'1Fc' 2 'Fz' [] [] [] 'P0702' [] [] [] [] []
'1Fc' 2 'Fz' [] 'P0702' 'P0801' [] [] [] [] [] []
'1Fj' 8 'Fr' 'P0702' [] [] [] [] [] [] [] []
'1FAH' 2 'Fo' [] [] [] [] [] [] 'P0882' 'P0702' []
'1FAH' 2 'Fo' [] [] [] [] [] [] 'P0882' 'P0702' 'P2700'
Data after Duplicates
'1FA' 2 'Fm' [] [] [] [] [] [] [] 'P2700' []
'1Fc' 2 'Fz' [] 'P0702' 'P0801' [] [] [] [] [] []
'1Fj' 8 'Fr' 'P0702' [] [] [] [] [] [] [] []
'1FAH' 2 'Fo' [] [] [] [] [] [] 'P0882' 'P0702' 'P2700'
Any help would be great on this.
First reading the question I thought this should be possible in 2 or 3 lines, but it took some lines of code to solve:
M={'1FA' 2 'Fm' [] [] [] [] [] [] [] 'P2700' []
'1Fc' 2 'Fz' [] [] [] 'P0702' [] [] [] [] []
'1Fc' 2 'Fz' [] 'P0702' 'P0801' [] [] [] [] [] []
'1Fj' 8 'Fr' 'P0702' [] [] [] [] [] [] [] []
'1FAH' 2 'Fo' [] [] [] [] [] [] 'P0882' 'P0702' []
'1FAH' 2 'Fo' [] [] [] [] [] [] 'P0882' 'P0702' 'P2700' }
%r contains the number of nonempty cells, you want those with highest r
r=sum(cellfun(#(x)~isempty(x),(M(:,4:end))),2);
%Create a index matrix which maps each string of first and third column to
%a double, which allows to use unique.
[~,~,index]=unique(M(:,1));
index(:,2)=[M{:,2}];
[~,~,index(:,3)]=unique(M(:,3));
%fill fourth colum with consecutive numbers, used to restore original
%ordering
index(:,4)=1:size(index,1);
%Next two lines, sort index to have rows with highetst r first
[~,sorted_most_content]=sort(-r);
index=index(sorted_most_content,:);
%Now first three columns of index should be unique and the best choice
%comes first, finally unique can be used.
[~,indices_unique_content,~]=unique(index(:,1:3),'rows');
%use previously appended consecutive numbers to get line numbers we want.
%sort restores original ordering.
unique_content_inorder=sort(index(indices_unique_content,4));
%The data you want:
M(unique_content_inorder,:)
I have a number of rows in a cell array with lots of extra space at the end of the rows as such:
'a' 'b' 'c' 'd' [] [] [] [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []
I would like to copy the second row onto the end of the first row, as such:
'a' 'b' 'c' 'd' '1' '2' '3' [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []
Please note that the code given above is an arbitrary example to demonstrate what I wish to do. In reality I will include this functionality as a step in a more complex function.
I have tried searching for the first empty element in the cell array row, but for some reason isempty does not see them as empty. Is there an alternative method that someone could point me towards?
EDIT:
After the steps carried out above, the second row will be deleted, giving:
'a' 'b' 'c' 'd' '1' '2' '3' [] []
'w' 'x' 'y' 'z' [] [] [] [] []
Although the real cell array will have many more rows than 3.
I think this does what you want. I've denoted your cell array as c.
n1 = find(cellfun('isempty',c(1,:)), 1); %// first empty cell in row 1
n2 = find(cellfun('isempty',c(2,:)), 1); %// first empty cell in row 2
c(1,n1:n1+n2-2) = c(2,1:n2-1); %// copy the relevant part of row 2 onto row 1
This automatically extends your cell horizontally if the number of non-empty cells in row 2 exceeds the number of empty cells in row 1.
Example: input:
c = {'a' 'b' 'c' 'd' [] [] [] [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []}
Output:
c =
'a' 'b' 'c' 'd' '1' '2' '3' [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []
Here's one general approach that uses the efficient logical indexing to select the non-empty cells, single call to cellfun('isempty' and does automatic extension as talked about in Luis's solution -
C = {
'a' 'b' 'c' 'd' [] [] [] [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []} %// Input cell array
N = 2; %//Number of rows to process, starting from 2 until the number of rows in C
Ct = C'; %//'# Transpose input cell array, as collecting elements that way is easier
vals = Ct(~cellfun('isempty',Ct(:,1:N))); %//'# elements from selected row(s)
C(1,1:numel(vals)) = vals; %// Place the values into the first row
With N = 2 which is the case stated in the problem, output would be -
C =
'a' 'b' 'c' 'd' '1' '2' '3' [] []
'1' '2' '3' [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] []
With N = 3, you would copy the second and third rows at the end of the first row. Thus, the output would be -
C =
'a' 'b' 'c' 'd' '1' '2' '3' 'w' 'x' 'y' 'z'
'1' '2' '3' [] [] [] [] [] [] [] []
'w' 'x' 'y' 'z' [] [] [] [] [] [] []
and so on.
I have a 50000 * 2 cell with number contents. Now I want to replace the second column which has numbers ranging from 1 to 10 with corresponding strings like 'airplane' for 1, 'automobile' for 2 and so on. What is the most efficient method for this?
I tried first by splitting the second column content to a new cell classes1 and coverted it to strings and tried replacing by applying the code below :
classes1(strcmp('1',classes1))={'airplane'};
classes1(strcmp('2',classes1))={'automobile'};
classes1(strcmp('3',classes1))={'bird'};
classes1(strcmp('4',classes1))={'cat'};
classes1(strcmp('5',classes1))={'deer'};
classes1(strcmp('6',classes1))={'dog'};
classes1(strcmp('7',classes1))={'frog'};
classes1(strcmp('8',classes1))={'horse'};
classes1(strcmp('9',classes1))={'ship'};
classes1(strcmp('10',classes1))={'truck'};
But that was not successfull. It only replaced '10' with 'truck'.
UPDATE : This code will actually work. But in my case strings ' 1' has to be used instead '1' (a space was missing).
Use this to extend to your big case -
%%// Create look up and numeral data cell arrays for demo
LOOKUP_CELL_ARRAY = {'airplane','automobile','chopper'};
IN_CELL_ARRAY = num2cell(round(1+2.*rand(10,2)))
%%// Replace the second column of data cell array with corresponding
%%// strings in the look up array
IN_CELL_ARRAY(:,2)= LOOKUP_CELL_ARRAY(cell2mat(IN_CELL_ARRAY(:,2)))
Output -
IN_CELL_ARRAY =
[2] [2]
[2] [2]
[2] [1]
[2] [2]
[3] [1]
[2] [3]
[1] [1]
[3] [3]
[2] [2]
[2] [3]
IN_CELL_ARRAY =
[2] 'automobile'
[2] 'automobile'
[2] 'airplane'
[2] 'automobile'
[3] 'airplane'
[2] 'chopper'
[1] 'airplane'
[3] 'chopper'
[2] 'automobile'
[2] 'chopper'
You can do it as follows with cellfun:
% replacement strings
R = {'airplane','automobile','bird','cat','deer', ...
'dog','frog','horse','ship','truck'};
% example data
nums = randi(10,100,1);
data(:,1) = num2cell(nums)
data(:,2) = cellstr(num2str(nums))
data =
[ 3] ' 3'
[ 1] ' 1'
[ 1] ' 1'
[ 8] ' 8'
[ 8] ' 8'
[ 8] ' 8'
[ 7] ' 7'
[ 9] ' 9'
[ 1] ' 1'
...
str2double(x) does not care about whether its '01' or '1':
% replicate number strings with strings
data(:,2) = cellfun(#(x) R( str2double(x) ), data(:,2) )
data =
[ 3] 'bird'
[ 1] 'airplane'
[ 1] 'airplane'
[ 8] 'horse'
[ 8] 'horse'
[ 8] 'horse'
[ 7] 'frog'
[ 9] 'ship'
[ 1] 'airplane'
...
You can do it just with indexing:
data = {'aa' 1
'bb' 3
'cc' 2
'dd' 6
'ee' 1
'ff' 5}; %// example data: two-col cell array, 2nd col is numbers
str = {'airplane','automobile','bird','cat','deer', ...
'dog','frog','horse','ship','truck'}; %// replacement strings
data(:,2) = str(vertcat(data{:,2})); %// do the replacing
I have the following:
a =
{1x1 cell} {1x1 cell} {1x1 cell} {1x1 cell}
where:
a{:}
ans =
'a'
ans =
'a'
ans =
'c'
ans =
'a'
I want to have the characters: a a c a
Since I need the characters to print using fprintf
fprintf won't accept a{:}
If I do a{1}{:} will consider only the first character a
How to fix this? Thanks.
If you only need the character vector 'aaca', you can use this:
a = {{'a'}, {'a'}, {'c'}, {'a'}};
a_CharVector = cellfun(#(x) char(x), a);
If you want the character vector 'a a c a ', you can use regexprep to add the spaces:
a_CharVectorWithSpaces = regexprep((cellfun(#(x) char(x), a)), '(.)', '$1 ');
To print a a c a with spaces and newline you can use this:
fprintf([ regexprep((cellfun(#(x) char(x), a)), '(.)', '$1 '), '\n' ]);
Edit: unnecessary anonymous function removed. #(x) is unnecessary in this case.
To get character vector 'aaca' this works:
a_CharVector = cellfun(#char, a);
And to get character vector 'a a c a ' you can use this:
a_CharVectorWithSpaces = regexprep((cellfun(#char, a)), '(.)', '$1 ');
To printf a a c a with newline:
fprintf([ regexprep((cellfun(#char, a)), '(.)', '$1 '), '\n' ]);
I have a matrix generated from the program written in Matlab something like this :
'A' 'B' 'C' 'D' 'E'
[ 4] [ 1] [ 0.9837] [ 0.9928] [0.9928]
[ 4] [ 1] [ 0.9995] [ 0.9887] [0.9995]
[ 4] [ 1] [ 0.9982] [ 0.9995] [0.9995]
[ 4] [ 1] [ 0.9959] [ 0.9982] [0.9887]
I am trying to extract the column 'D' without the header 'D'.
I can put into a temporary variable and then extract the column data. But I am wondering, if it could be done in a single step.
Thanks
If your variable is data, then data(2:end,4) should do it.
Edit:
For example:
>> data
data =
'A' 'B' 'C' 'D' 'E'
[4] [1] [0.9837] [0.9928] [0.9928]
[4] [1] [0.9995] [0.9887] [0.9995]
[4] [1] [0.9982] [0.9995] [0.9995]
[4] [1] [0.9959] [0.9982] [0.9887]
>> data(2:end,4) %Extract the data as a cell array
ans =
[0.9928]
[0.9887]
[0.9995]
[0.9982]
>> cell2mat(data(2:end,4)) %Convert to a numeric (typical) array
ans =
0.9928
0.9887
0.9995
0.9982