Matlab Array has strange syntax - matlab

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!

Related

Why does cell2mat convert a cell array into a matrix of characters, instead of a matrix of cell contents?

I have this cell array
>> FooCellArray
FooCellArray =
1×7 cell array
Columns 1 through 4
{'Foo1'} {'Foo2'} {'Foo3'} {'Foo4'}
Columns 5 through 7
{'Foo5'} {'Foo6'} {'Foo7'}
cell2mat() converts the array into a character array instead of a 1x7 or 7x1 matrix of 'Foo1' ... 'Foo7'.
>> (cell2mat(FooCellArray))'
ans =
28×1 char array
'F'
'o'
'o'
'1'
'F'
'o'
'o'
'2'
'F'
'o'
'o'
'3'
'F'
'o'
'o'
'4'
....
Why?
cell2mat is doing precisely the correct thing as documented here. Each cell element is char vector of size 1xN. Your overall cell array is 1xN. cell2mat concatenates the contents of every cell in the "natural" direction as defined by the shape of the cell array. Your original cell looks a bit like this:
FooCellArray = [{'Foo1'}, {'Foo2'}]
The effect of cell2mat is basically as if you removed the {}, so you're left with
cell2mat(FooCellArray) --> ['Foo1', 'Foo2']
And therefore this gets concatenated into a single char vector 'Foo1Foo2'.
Compare with vectors of double instead of vectors of char:
>> FooCellArray = [{[1,2,3]}, {[4,5,6]}]
FooCellArray =
1×2 cell array
{[1 2 3]} {[4 5 6]}
>> cell2mat(FooCellArray)
ans =
1 2 3 4 5 6
With a smaller starting example:
FooCellArray = {'Foo1','Foo2','Foo3'} ;
If your MATLAB version is >= 2017b
You can directly use the function convertCharsToStrings:
>> convertCharsToStrings(FooCellArray)
ans =
1×3 string array
"Foo1" "Foo2" "Foo3"
The benefit of this method is that it will work even if the strings contained in your cell array are not all of the same length. You can transpose it if you want it as a column instead of line vector. Note the terminology of the result type, it is a string array.
If you MATLAB version is older AND if all the strings in the cell array have the same length, you could convert your cell array into a 2D character array:
>> reshape(cell2mat(FooCellArray),4,[]).'
ans =
3×4 char array
'Foo1'
'Foo2'
'Foo3'
For this one, transposition wouldn't really make sense. This result type is a char array, which are ok when they are simple vector but they get quite unwieldy once they are in 2D. Mainly because they are not as flexible as strings, each line has to have the same number of elements. So as #Adriaan pointed at, if one of your cell contained Foo24 then the reshape command would error.
Edit: Or as Chris Luengo kindly mentionned in comment, a simpler command to get exactly the same result:
>> cell2mat(FooCellArray.')
ans =
3×4 char array
'Foo1'
'Foo2'
'Foo3'
This has the same restriction, all the cell contents must have the same number of characters or the command will error.

How to append an empty array to a cell array

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.

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);

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}};

What's the difference between {} and [] in MATLAB?

>> A={1 2;2 3}
A =
[1] [2]
[2] [3]
>> A=[1 2;2 3]
A =
1 2
2 3
It seems to me they are essentially the same thing?
{}'s are for cells. []'s are for arrays/matrices.
[] is an array-related operator. An array can be of any type - array of numbers, char array (string), struct array or cell array. All elements in an array must be of the same type!
Example: [1,2,3,4]
{} is a type. Imagine you want to put items of different type into an array - a number and a string. This is possible with a trick - first put each item into a container {} and then make an array with these containers - cell array.
Example: [{1},{'Hallo'}] with shorthand notation {1, 'Hallo'}
It is unnecessary to put objects of the same type (doubles) into a cell array like in your example.
No. They are not at all the same thing. The only aspect that is the same is the resulting shape.
An array (that which you build with []) is something you can use to do linear algebra. One number in each element.
A = [1 2 3;4 5 6;7 8 9];
[3 5 7]*A*[2 3 5]'
ans =
915
A cell array is a general container, that will hold any object, any matlab variable entirely in each cell. Thus we can create a cell array composed of elements of any shape and size.
C = {'The' 'quick' 'brown' 'fox' 'jumps' 'over' 'the' 'lazy' 'dog'};
C is a cell array with 9 elements in it. We can put any class of variable in there.
C = {'asfghhrstyjtysj', 1:5, magic(4), sqrt(-1)}
C =
'asfghhrstyjtysj' [1x5 double] [4x4 double] [0 + 1i]
We could even create a cell array where each cell contains only a single scalar number. But there would be no real point in doing so, as we cannot do arithmetic operations using cell arrays.
If you relate it to object oriented programming,
cells {} are like objects and [] is for arrays
Elements of different data types which get inside {} become cells or elements of data type cell. Elements inside [] retain their data type and make an array of that data type. Few examples below:
p = ['my', 'string'];
q = [int8(1), int8(2), int8(3)];
r = [0.11, 0.22, 0.33];
s = {'my', 'string'};
t = {1,2,3};
u = {0.11, 0.22, 0.33};
v = {int8(1), int8(2), int8(3)};
>> whos
Name Size Bytes Class Attributes
p 1x8 16 char
q 1x3 3 int8
r 1x3 24 double
s 1x2 240 cell
t 1x3 360 cell
u 1x3 360 cell
v 1x3 339 cell