Combine Columns of Cell Array Matlab - matlab

I have a 2D cell array with dynamic row sizes and column sizes. One example:
cell3 = [{'abe' 'basdasd' 'ceee'}; {'d' 'eass' 'feeeeeeeeee'}]
Gives: (with dimension 2 by 3)
'abe' 'basdasd' 'ceee'
'd' 'eass' 'feeeeeeeeee'
I want to be able to combine the columns and reproduce a aggregate string cell array where each string is separated by a single white space. Any idea how to do that?
So the output i am looking for is:
'abe basdasd ceee'
'd eass feeeeeeeeee'
The final dimension is 2 by 1.
Is this possible?

Apply strjoin either in a loop or via cellfun. The latter:
>> cellRows = mat2cell(cell3,ones(size(cell3,1),1),size(cell3,2));
>> out = cellfun(#strjoin,cellRows,'uni',0)
out =
'abe basdasd ceee'
'd eass feeeeeeeeee'

Solution without loops or cellfun:
[m n] = size(cell3);
cellCols = mat2cell(cell3,m,ones(1,n)); %// group by columns
cellColsSpace(1:2:2*size(cell3,2)-1) = cellCols; %// make room (columns)...
cellColsSpace(2:2:2*size(cell3,2)-1) = {{' '}}; %// ...to introduce spaces
%// Note that a cell within cell is needed, because of how strcat works.
result = strcat(cellColsSpace{:});

Related

Extracting field from cell array of structure in matlab

I have a cell array (let's say size 10) where each cell is a structure with the same fields. Let's say they all have a field name x.
Is there a way to retreive in a vector the value of the field x for all the structure in the cell array? I would expect the function to return a vector of size 10 with in position 1, the value of the field x of the structure in cell 1 etc etc...
EDIT 1:
The structure in the cell array have 1 field which is the same for all but some others which are different.
First convert your cell array of structures, c, (with identical field names in the same order) to a structure array:
c = cell2mat(c)
Then, depending on the data types and sizes of the elements of the field, you may be able to use
[c.x]
to extract your vector of field x values in the "standard" way.
It is also possible that you can skip the conversion step and use cellfun(#(e)e.x, c) to do the extraction in one go.
The below code creates a cell array of structures, and extracts field 'x' of each structure to a vector v.
%create a cell array of structures
s1.a = 'hello';
s1.x = 1;
s2.a = 'world';
s2.x = 2;
c{1} = s1;
c{2} = s2;
v = zeros(1,2);
%extract to vector
for idx=1:size(c,2)
v(1,idx) = c{idx}.x;
end
Let's say you have
c = {s1, s2, s3, ...., sn};
where common field is 'field_1', then you have two options
Use cell2mat.
cc = cell2mat(c); % which converts your cell array of structs into an array of structs
value = [cc.field_1]; % if values are number
or
value = {cc.field_1}; % if values are characters, for example
Another option is to use cellfun.
If the field values are characters, you should set "UniformOutput" to "false"
value = cellfun(#(x) x.field_1, c, 'UniformOutput', false)
The first option is better. Also, try to avoid using cell/cellfun/arrayfun whenever you can, vectors are way faster and even a plain for loop is more effecient

Extract data from a Cell Array using a vector and converting into an array

I have a cell array [5x1] which all cells are column vectors such as:
exInt =
[46x1 double]
[54x1 double]
[40x1 double]
[51x1 double]
[ 9x1 double]
I need to have a vector (vec) containing the cells in extInt I need to extract and then I have to convert these into a single column array. Such as:
vec = [1,3];
Output = cell2mat(extInt{vec})
Output should become something an array [86x1 double].
The way I have coded I get:
Error using cell2mat
Too many input arguments.
If possible, I would like to have a solution not using a loop.
The best approach here is to use cat along with a comma-separted list created by {} indexing to yield the expected column vector. We specify the first dimension as the first argument since you have all column vectors and we want the output to also be a column vector.
out = cat(1, extInt{vec})
Given your input, cell2mat attempts to concatenate along the second dimension which will fail for your data since all of the data have different number of rows. This is why (in your example) you had to transpose the data prior to calling cell2mat.
Update
Here is a benchmark to compare execution times between the cat and cell2mat approaches.
function benchit()
nRows = linspace(10, 1000, 100);
[times1, times2] = deal(zeros(size(nRows)));
for k = 1:numel(nRows)
rows = nRows(k);
data = arrayfun(#(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
vec = 1:2:numel(data);
times1(k) = timeit(#()cat_method(data, vec));
data = arrayfun(#(x)rand(randi([10, 50], 1), 1), 1:rows, 'uni', 0);
vec = 1:2:numel(data);
times2(k) = timeit(#()cell2mat_method(data, vec));
end
figure
hplot(1) = plot(nRows, times1 * 1000, 'DisplayName', 'cat');
hold on
hplot(2) = plot(nRows, times2 * 1000, 'DisplayName', 'cell2mat');
ylabel('Execution Times (ms)')
xlabel('# of Cell Array Elements')
legend(hplot)
end
function out = cat_method(data, vec)
out = cat(1, data{vec});
end
function out = cell2mat_method(data, vec)
out = cell2mat(data(vec)');
end
The reason for the constant offset between the two is that cell2mat calls cat internally but adds some additional logic on top of it. If you just use cat directly, you circumvent that additional overhead.
You have a small error in your code
Change
Output = cell2mat(extInt{vec});
to
Output = cell2mat(extInt(vec));
For cells, both brackets and parentheses can be used to get information. You can read some more about it here, but to summarize:
Use curly braces {} for setting or getting the contents of cell arrays.
Use parentheses () for indexing into a cell array to collect a subset of cells together in another cell array.
In your example, using brackets with index vector vec will produce 2 separate outputs (I've made a shorter version of extInt below)
extInt = {[1],[2 3],[4 5 6]};
extInt{vec}
ans =
1
ans =
4 5 6
As this is 2 separate outputs, it will also be 2 separate input to the function cell2mat. As this function only takes one input you get an error.
One alternative is in your own solution. Take the two outputs and place them inside a new (unnamed) cell
{extInt{vec}}
ans =
[1] [1x3 double]
Now, this (single) result goes into cell2mat without a problem.
(Note though that you might need to transpose your result before depending on if you have column or row vectors in your cell. The size vector (or matrix) to combine need to match/align.)
Another way as to use parentheses (as above in my solution). Here a subset of the original cell is return. Therefore it goes directly into the cell2matfunction.
extInt(vec)
ans =
[1] [1x3 double]
I have been messing around and I got this working by converting this entry into a new cell array and transposing it so the dimensions remained equivalent for the concatenating process
Output = cell2mat({extInt{vec}}')
use
Output = cell2mat(extInt(vec))
Since you want to address the cells in extInt not the content of the cells
extInt(vec)
extInt{vec}
try those to see whats going on

matlab: append a character in a martix

I have a matrix, say
A= zeros(5,5,5,5);
and assigned a decimal value for each cell
Now I want to add a character 'x' for every cell
How should I do it?
I have tried to convert A to cell matrix using num2cell
but when I add the 'x' to it, I got the out of range warning and my value disappeared, leaving a single 'x' in every cell
A=zeros(5,5,5,5)
%some calculation for some decimal value
for %something
assign value to every cell
end
A=num2cell(A)
A=concat(A,'x')
If you want to transform 3 to 3x, you cannot store it in a number format any longer, but you have to transform it to string. However, once it is a string, it's very easy to add a letter:
A = zeros(5,5,5,5);
%// fill A with numbers
%// convert to cell
C = num2cell(A);
%// transform all numbers in C to strings using num2str
%// and add the letter 'x' by catenation
%// cellfun applies the function to each element of the cell array
C = cellfun(#(x)[num2str(x),'x'], C, 'UniformOutput', false);
Note that as #Daniel correctly states, you can skip a step in the process and run arrayfun(#(x)[num2str(x),'x'], A, 'UniformOutput', false); on the numeric array directly - the 'UniformOutput',false statement means that arrayfun will return the results in a cell array.
similarly:
B = cell(5,5,5,5);
D = cellfun(#(c) [c '0'],B,'UniformOutput',0);
E = cellfun(#(c) [c 'x'],D,'UniformOutput',0);

Matlab - Two Column Matrices into One Column Matrix with rows elements

I have two column matrices:
size(X) = 50 x 1
size(Y) = 50 x 1
which I got from ind2sub
I want to create a structure str such that
str(i).XYZ returns [X(i), Y(i)] for i in [1,50]
I am trying to use
str = struct('XYZ', num2cell([X,Y]));
However, I believe for this to work properly, I need to modify [X,Y] to a matrix of row vectors, each row vector being [X(i), Y(i)]. Not sure if there is a better approach
You are basically on the right way, but num2cell([X,Y]) creates a 2x50 cell, which results in a 2x50 struct. You want to split your input matrix [X,Y] only among the second dimensions so each cell is a 2x1, use num2cell([X,Y],2)
str = struct('XYZ', num2cell([X,Y],2));
Concatenate the two vectors, convert from matrix to cell, and then from cell to struct array:
str = cell2struct(mat2cell([X Y], ones(1,size(X,1)), size(X,2)+size(Y,2) ).', 'XYZ');

In MATLAB how can I set all the values of a matrix to string?

I have a MATLAB matrix, that is 1000x4, to use as an input for a function. I need to add a new column that contains a certain string. So how can I make a new column where all the values are 'TEST'?
Since it's a little unclear what you want, here are some options:
To make a 1000-by-4 matrix where each row is 'TEST', you can use the function REPMAT:
M = repmat('TEST',1000,1);
To add 'TEST' to the end of each row of a 1000-by-4 matrix of characters, you can use the function STRCAT:
M = repmat('a',1000,4); %# Sample matrix filled with 'a'
M = strcat(M,'TEST'); %# Append 'TEST' to each row of M
If your 1000-by-4 matrix is a numeric array instead of an array of characters, you will have to use cell arrays to combine the different types of data. Here's one way you can do this:
M = rand(1000,4); %# A matrix of random numeric values
M = num2cell(M,2); %# Put each row of M in a cell, making
%# a 1000-by-1 cell array
M(:,2) = {'TEST'}; %# Add a second column to the cell array,
%# where each cell contains 'TEST'
A matrix cannot contain a string (like 'TEST').
You need to use a cell array
If this is an existing matrix M of cell strings,
M(:,end+1) = {'TEST'};