How to append an empty array to a cell array - matlab

How do you append an empty array to a (non-empty) cell array?
For example, starting with
c={[1],[2]}
desire
c={[1],[2],[]}
Concatenation would remove the empty array whether it is double, char or cell.

In addition to #Adriaan's answer, note that you can also do this with concatenation, if you are careful.
>> c = {1, 2}
c =
1x2 cell array
{[1]} {[2]}
>> [c, {[]}]
ans =
1x3 cell array
{[1]} {[2]} {0x0 double}
The trick here is to concatenate explicitly with another cell (your question suggests you tried [c, []] which does indeed do nothing at all, whereas [c, 1] automatically converts the raw 1 into {1} before operating).
(Also, while pre-allocation is definitely preferred where possible, in recent versions of MATLAB, the penalty for growing arrays dynamically is much less severe than it used to be).

You can just append it by using end+1:
c={[1],[2]}
c =
[1] [2]
c{end+1} = [] % end+1 "appends"
c =
[1] [2] []
MATLAB note: appending is usually used as a way to grow an array in size within a loop, which is not recommended in MATLAB. Instead, use pre-allocation to initially apply the final size whenever possible.

Related

How to apply a binary function to a cell array and a double array

I have a cell of arrays (e.g. character vectors) that takes positional indexing and a double array containing positing integers that are meant to be array indices. Is there a native function that can apply the indices to the cell of arrays?
For example,
A={'abc','asdfc','aojcdfw','casd'};
B=[3,5,4,1];
Is there a native function that can output the following?
{A{1}(B(1):end), A{2}(B(2):end), A{3}(B(3):end), A{4}(B(4):end)}
extractAfter does exactly this.
>> extractAfter(A, B-1)
ans =
1×4 cell array
{'c'} {'c'} {'cdfw'} {'casd'}
You can do it with a cellfun. For cellfun, all inputs must be cells, so I first convert B to cell using num2cell.
cellfun(#(a,b) a(b:end), A, num2cell(B), 'UniformOutput', false);

cellfun with conditionals in MATLAB

Is it possible to use cellfun with a conditional. For example, I have a 144x53 cell array, where the first four columns are of type string, the rest are floats. However, among the numbers, there are empty cells. I wonder if it is possible to use cellfun(#(x)sqrt(x), cellarray) with my array. As it is know, its not possible due to strings and empty cells. Otherwise, this is the solution that I use,
for n = 1:length(results)
for k = 1:length(results(1,:))
if ~isstr(results{n,k})
results{n, k} = sqrt(results{n,k});
end
end
end
Otherwise, is it possible to do a vectorization here?
You can create a logical array by checking if each element is numeric. And then use this to perform your cellfun operation on the subset of the cell array that contains numeric data.
C = {1, 2, 'string', 4};
% Logical array that is TRUE when the element is numeric
is_number = cellfun(#isnumeric, C);
% Perform this operation and replace only the numberic values
C(is_number) = cellfun(#sqrt, C(is_number), 'UniformOutput', 0);
% 1 1.4142 'string' 2
As pointed out by #excaza, you may also consider leaving it as a loop as it is more performant on newer versions of MATLAB (R2015b and newer).

Assign to subset of cell array - MATLAB

I'm trying to assign a cell array to a subset of another cell array, like
data_date1 = '08/15/2003';
data_date2 = '08/16/2003';
data_date3 = '08/17/2003';
num1 = 56;
num2 = 23;
num3 = 2;
cell_1={data_date1, num1; data_date2, num2};
array=cell(3,1)
array{1:2} = cell_1 % problem line
array{3} = {data_date3, num3}
For context, the cell_1 array is the output of another function, and I'm trying to fill array in a loop in another function.
What's the proper method for this?
To copy cell array elements from one cell array to another without having to access the content of the element you can use the standard matrix indexing syntax, which uses the brackets (i,j) instead of the curly braces {i,j}.
let M be a cell array:
M(i,j) return a 1x1 cell, copy of the (i,j) element of M
M{i,j} return the content of the (i,j)th element of M. This could be of any type, depending on what the cell content was.
Cell array as a standard array
So in your case you can assign subarray to a larger array, but you just have to watch your indexing (the size in all dimensions should be correct).
So if you declare a 3x2 cell array:
array=cell(3,2)
Then you can assign your 2x2 sub array to it, if you have the address right:
>> array(1:2,:) = cell_1
array =
'08/15/2003' [56]
'08/16/2003' [23]
[] []
And then add your last elements:
>> array(3,:) = {data_date3, num3}
array =
'08/15/2003' [56]
'08/16/2003' [23]
'08/17/2003' [ 2]
This way treat your array like an nxm standard array, just consider the cell type like a specific type (like you would have double or uint8 array) without having to know the type of the data they contain inside.
Nested Cell array
Cell array have this capacity to be nested. So a single cell of a cell array could contain another whole cell array (where each cell could contain cell array etc ... although I wouldn't recommend nesting too deep).
In this configuration, you final array could be as you defined it, a 3x1 cell array, where each cell would contain another 1x2 cell array. You can also assign subarray to this type, but again the sizes of source and destinations have to match. So if you prefer this form, you would have to define your cell_1 slightly differently:
>> cell_1= { {data_date1, num1} ; { data_date2, num2} }
cell_1 =
{1x2 cell}
{1x2 cell}
Note the nesting of cell array into the larger cell array, in order to have a 1x2 subarray, which you can now assign to your main array:
>> array=cell(3,1) ;
array(1:2) = cell_1
array =
{1x2 cell}
{1x2 cell}
[]
Now to add the last element you have two different ways but you need to be careful:
array(3) = { {data_date3, num3} } %// assign a 1x2 sub array to the 3rd element of "array"
array{3} = {data_date3, num3} %// set the content of the 3rd element of "array" as a 1x2 cell array
These two lines are equivalent, they produce the same result. You can do either or, depending on the style you prefer (or may be forced by the shape your data are coming in).
There is error is because you cannot use indexing with cell array like that. Either you must do like:
array{1} = cell_1;
array{2} = cell_1;
array{3} = {data_date3, num3};
or you can try repmat (no need initialization array = cell(3,1)), though I don't know how long is your array:
array = repmat({cell_1}, 2, 1);
% or: array = {cell_1; cell_1}
array{3} = {data_date3, num3};
Another way if array is short:
array = {cell_1; cell_1; {data_date3, num3}};

Matlab Array has strange syntax

In Matlab, we use textscan to get a cell array from a file or somewhere. But the behavior of the cell array is so strange.
There is the sample code:
>> str = '0.41 8.24 3.57 6.24 9.27';
>> C = textscan(str, '%3.1f %*1d');
>> C
C =
[5x1 double]
We can know that C is a cell array of size 5 * 1. When I use C{1}, C{1}{1} and C(1). I get the following result:
>> C{1}
ans =
0.4000
8.2000
3.5000
6.2000
9.2000
>> C{1}{1}
Cell contents reference from a non-cell array object.
>> C(1)
ans =
[5x1 double]
Why I cannot use C{1}{1} to get the element from the cell array ? Then how can I get the elements from that cell array ?
An example I found on the Internet is :
%% First import the words from the text file into a cell array
fid = fopen(filename);
words = textscan(fid, '%s');
%% Get rid of all the characters that are not letters or numbers
for i=1:numel(words{1,1})
ind = find(isstrprop(words{1,1}{i,1}, 'alphanum') == 0);
words{1,1}{i,1}(ind)=[];
end
As words{1,1}{i,1}(ind)=[] show, what is the mechanism of using {}?
Thanks
Then how can I get the elements from that cell array ?
C = C{:}; % or C = C{1};
Access values by C(1), C(2) and so on
There is a slightly different syntax for indexing into cell arrays and numerical arrays. Your output
>> C
C =
[5x1 double]
is telling you that what you have is a 1x1 cell array, and in that 1 cell is a 5x1 array of doubles. Cell arrays are indexed into with {}, while 'normal' arrays are indexed into with ().
So you want to index into the first element of the cell array, and then index down to the first value in the 5x1 array of doubles using C{1}(1). To get the second value - C{1}(2), and so forth.
If you're familiar with other programming languages, cell arrays are something like arrays of pointers; the operator A(n) is used to get the nth element of the array A, while A{n} gets the object pointed to by the nth element of the array A (or 'contained in the nth cell of cell array A'). If A is not a cell array, A{n} fails.
So, knowing that C is a cell array, here's why you got what you got in the cases you tried -
C{1} returns the 5x1 double array contained in the first cell of C.
C{1}{1} gets the object (call it B) contained in the first cell of C, and then tried to get the object contained in the first cell of B. It fails because B is not a cell array, it is a 5x1 double array.
And C(1) returns the first element of C, which is a single cell containing a 5x1 double array.
But C{1}(1) would get you the first element of the 5x1 array contained in the first cell of C, which is what you are looking for. As #Cheery above me noted, it's probably easier, instead of writing C{1}(1), C{1}(2), ... to remove the 'cell-level' indexing by setting C=C{1}, which means C is now a 5x1 double array, and you can get the elements of it using C(1), C(2), ... Hope that makes sense!

Substrings from a Cell Array in Matlab

I'm new to MATLAB and I'm struggling to comprehend the subtleties between array-wise and element wise operations. I'm working with a large dataset and I've found the simplest methods aren't always the fastest. I have a very large Cell Array of strings, like in this simplified example:
% A vertical array of same-length strings
CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};
I'm trying to extract an array of substrings, for example:
'a1'
'b1'
'c1'
'd1'
I'm happy enough with an element-wise reference like this:
% Simple element-wise substring operation
MySubString = CellArrayOfStrings{2}(3:4); % Expected result is 'b1'
But I can't work out the notation to reference them all in one go, like this:
% Desired result is 'a1','b1','c1','d1'
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!
I know that Matlab is capable of performing very fast array-wise operations, such as strcat, so I was hoping for a technique that works at a similar speed:
% An array-wise operation which works quickly
tic
speedTest = strcat(CellArrayOfStrings,'hello');
toc % About 2 seconds on my machine with >500K array elements
All the for loops and functions which use behind-the-scenes iteration I have tried run too slowly with my dataset. Is there some array-wise notation that would do this? Would somebody be able to correct my understanding of element-wise and array-wise operations?! Many thanks!
I can't work out the notation to reference them all in one go, like this:
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!
This is because curly braces ({}) return a comma-separated list, which is equivalent to writing the contents of these cells in the following way:
c{1}, c{2}, and so on....
When the subscript index refers to only one element, MATLAB's syntax allows to use parentheses (()) after the curly braces and further extract a sub-array (a substring in your case). However, this syntax is prohibited when the comma separated lists contains multiple items.
So what are the alternatives?
Use a for loop:
MyArrayOfSubStrings = char(zeros(numel(CellArrayOfStrings), 2));
for k = 1:size(MyArrayOfSubStrings, 1)
MyArrayOfSubStrings(k, :) = CellArrayOfStrings{k}(3:4);
end
Use cellfun (a slight variant of Dang Khoa's answer):
MyArrayOfSubStrings = cellfun(#(x){x(3:4)}, CellArrayOfStrings);
MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
If your original cell array contains strings of a fixed length, you can follow Dan's suggestion and convert the cell array into an array of strings (a matrix of characters), reshape it and extract the desired columns:
MyArrayOfSubStrings =vertcat(CellArrayOfStrings{:});
MyArrayOfSubStrings = MyArrayOfSubStrings(:, 3:4);
Employ more complicated methods, such as regular expressions:
MyArrayOfSubStrings = regexprep(CellArrayOfStrings, '^..(..).*', '$1');
MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
There are plenty solutions to pick from, just pick the one that fits you most :) I think that with MATLAB's JIT acceleration, a simple loop would be sufficient in most cases.
Also note that in all my suggestions the obtained cell array of substrings cell is converted into an array of strings (a matrix). This is just for the sake of the example; obviously you can keep the substrings stored in a cell array, should you decide so.
cellfun operates on every element of a cell array, so you could do something like this:
>> CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};
>> MyArrayofSubstrings = cellfun(#(str) str(3:4), CellArrayOfStrings, 'UniformOutput', false)
MyArrayofSubstrings =
'a1'
'b1'
'c1'
'd1'
If you wanted a matrix of strings instead of a cell array whose elements are the strings, use char on MyArrayOfSubstrings. Note that this is only allowed when each string is the same length.
You can do this:
C = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'}
t = reshape([C{:}], 6, [])'
t(:, 3:4)
But only if your strings are all of equal length I'm afraid.
You can use char to convert them to a character array, do the indexing and convert it back to cell array
A = char(CellArrayOfStrings);
B = cellstr(A(:,3:4));
Note that if strings are of different lengths, char pads them with spaces at the end to create the array. Therefore if you index for a column that is beyond the length of one of the short strings you may receive some space characters.