How can I concatenate vector and cell in MATLAB? - matlab

I have matrix F of dimension 5 X 3. For example:
F= [1 12 13;
2 23 24;
3 34 35;
4 45 46;
5 56 57]
and I have a label cell of size 1X1 with entry 'v' i.e.
>> label
label =
'v'
and size of F is given by :
>> [m n]=size(F)
m=
5
n =
3
I want my output to look like:
>> F
F =
1 12 13 v
2 23 24 v
3 34 35 v
4 45 46 v
5 56 57 v
How can I concatenate the cell with the matrix to get this output?

To create an array that contains both numeric and non-numeric data, you need to put everything into a cell array (replace label by {label} in case it isn't a cell array):
Fcell = [ num2cell(F), repmat(label,size(F,1),1)]
You can then access individual numbers/letters using the curly brackets:
Fcell{2,2}
ans =
23

As #Jonas described, converting it to cells is the way to go when you want to access the data for further use.
However, if you are solely interested in seeing the data on the screen and don't like the brackets this is also an option:
Fcell = [num2str(F) repmat([' ' label{1}],size(F,1),1)]
If your label is actually a char it should work like this:
Fcell = [num2str(F) repmat([' ' label],size(F,1),1)]

Related

Repeat row vector as matrix with different offsets in each row

I want to repeat a row vector to create a matrix, in which every row is a slightly modified version of the original vector.
For example, if I have a vector v = [10 20 30 40 50], I want every row of my matrix to be that vector, but with a random number added to every element of the vector to add some fluctuations.
My matrix should look like this:
M = [10+a 20+a 30+a 40+a 50+a;
10+b 20+b 30+b 40+b 50+b;
... ]
Where a, b, ... are random numbers between 0 and 2, for an arbitrary number of matrix rows.
Any ideas?
In Matlab, you can add a column vector to a matrix. This will add the vector elements to each of the row values accordingly.
Example:
>> M = [1 2 3; 4 5 6; 7 8 9];
>> v = [1; 2; 3];
>> v + M
ans =
2 3 4
6 7 8
10 11 12
Note that in your case v is a row vector, so you should transpose it first (using v.').
As Sardar Usama and Wolfie note, this method of adding is only possible since MATLAB version R2016b, for earlier versions you will need to use bsxfun:
>> % instead of `v + M`
>> bsxfun(#plus, v, M)
ans =
2 4 6
5 7 9
8 10 12
If you have a MATLAB version earlier than 2016b (when implicit expansion was introduced, as demonstrated in Daan's answer) then you should use bsxfun.
v = [10 20 30 40 50]; % initial row vector
offsets = rand(3,1); % random values, add one per row (this should be a column vector)
output = bsxfun(#plus,offsets,v);
Result:
>> output =
10.643 20.643 30.643 40.643 50.643
10.704 20.704 30.704 40.704 50.704
10.393 20.393 30.393 40.393 50.393
This can be more easily understood with less random inputs!
v = [10 20 30 40 50];
offsets = [1; 2; 3];
output = bsxfun(#plus,offsets,v);
>> output =
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
Side note: to get an nx1 vector of random numbers between 0 and 2, use
offsets = rand(n,1)*2

What is meant by variable = (matrix,scalar) in Octave?

a=magic(5)
k=a,3
When I print k, it simply shows a.
m=size(a,3)
n=size(a,6)
when I print m and n, they print different values.
Anyone please explain what this function is?
On Octave 4.2.1
k=a,3
assigns the matrix a to the variable k, then, as a second instruction, prints on the CommandWindow the value 3.
The , (comma) is used in order to have two instruction on the same row.
An alterntive could be replacing the , with the ; which has the effect of suppressing the output on the CommandWindow of the assignment k=a
With respect to
m=size(a,3)
n=size(a,6)
the second parameter n the call to size specifies the dimension of the matrix (the first parameter) for which you want to know the size.
a is a two "dimensional" matrix of size (5 x 5) while the instruction size(a,3) looks for the size of the third dimension of a.
In a similar way, size(a,6) looks for the size of the a's sixth dimension. In these case, the a is considered as (5 x 5 x 1) and (5 x 5 x 1 x 1 x 1 x 1)
The return value, for is 1
This is the output in the CommandWondow:
>> a=magic(5)
a =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
>> k=a,3
k =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
ans = 3
>> m=size(a,3)
m = 1
>> n=size(a,6)
n = 1
In matlab / octave, there are three ways to terminate an expression (e.g. 1+2):
With a semicolon ;
With a comma ,
With a newline (i.e. pressing enter)
The first one (i.e. the semicolon) when used, evaluates the expression, but suppresses its output. The other two (i.e. the comma and the newline), both evaluate the statement and also display its result.
Why have both a comma and a newline? Because, with a comma, you can evaluate multiple expressions on the same line (and have all of them display their results).
Note: Given the fact that most people write their expressions in separate lines, the comma tends not to be used very much, so it is less known.
Examples:
octave:1> 1+2, 3+4
ans = 3
ans = 7
octave:2> 1+2; 3+4;
octave:3> 1+2; 3+4
ans = 7
octave:4> 1+2, 3+4;
ans = 3
octave:5> for i = 1:3; i; end % output in each iteration is suppressed
octave:6> for i = 1:3; i, end % whereas with a comma, output is not suppressed
i = 1
i = 2
i = 3
Therefore your statements:
a = magic(5)
k = a, 3
are essentially equivalent to
a = magic(5) % newline used: display value of a after assignment
k = a, % comma used, assign value of a to k, then display k
3 % newline used: displays the value '3' after pressing enter
Furthermore the size function doesn't do what you think it does. size(a,3) returns the size of array a in the 3rd dimension.

Use Matlab to compare columns in different cell arrays

I'm trying to compare two cell arrays that contain both characters and numbers. I would like to compare two specific columns and then return the values in another related column.
For example, I have two cell arrays of the forms:
One= Two=
[A 2 10 [A 1 2 76
B 2 11 B 1 2 78
A 5 22 C 1 2 80
B 5 23 D 1 4 98
A 6 28 E 1 4 99
B 6 28 F 1 4 100
C 6 28] G 1 6 110]
And I want to be able to find everywhere column 2 of 'One' equals column 3 of 'Two' and return the specific value in column 4 of 'Two.' So for this example, I would obtain a result that is:
Three=
[76
78
80
110]
Any help would be appreciated.
Option 1: convert to numeric array first
X = cell2mat(One(:,2:end));
Y = cell2mat(Two(:,2:end));
result = Y(X(:,1)==Y(:,2),3)
Option 2: convert to numeric array at various points
result = cell2mat(Two(cell2mat(One(:,2))==cell2mat(Two(:,3)),4))
Option 3: convert cell to table first
T1 = cell2table(One);
T2 = cell2table(Two);
result = T2.Two4(T1.One2==T2.Two3)
Option 4: abuse how Matlab cell arrays and numeric arrays work
result = [Two{([One{:,2}]==[Two{:,3}])',4}]'

Search particular matrix in cell array

So, I have this cell array contains n x 2 matrix in each cell. Here is the sample data :
[16 17;17 17]
<6x2 double>
<52x2 double>
[17 17;17 18]
[17 18;17 17]
What I am going to do is eliminate the duplicated matrix (matrices with same values or reversed values). in this case is [17 18; 17 17] (5th row), because we already have [17 17; 17 18] (4th row)
I tried using unique function but it says that the function just worked for strings. I also tried to find it with cellfun like this
cellfun(#(x) x==whatToSearch, lineTraced, 'UniformOutput', false)
but it says 'Matrix dimension must agree'
Thanks in advance.
Here is a solution. Given a m x 1 column cell array C of matrices, this code deletes the equivalent duplicates. (Here it will delete the 4th and 5th matrices, which are equivalent to the 1st).
C{1} = magic(3);
C{2} = magic(4);
C{3} = magic(5);
C{4} = C{1};
C{5} = flipud(C{1});
myEq = #(A,B) isequal(A,B) | isequal(A,flipud(B)); %// equivalence operator tests for same or up-down flipped matrix
C = C(:); %// ensure the cell array is a column
Crep = repmat(C,1,size(C,1)); %// repeat cell array along rows to get a square
comp = cellfun(myEq,Crep,Crep'); %'//get a comparison matrix by comparing with transpose
comp = tril(comp) - eye(size(comp)); %// ignore upper triangle and diagonal
idx = find( sum(comp,2)==0 ); %// get index of matrices we want to keep
result = C(idx); %// get result
The output is deletes the 4th and 5th matrices, leaving the first three magic matrices:
>> result
result =
[3x3 double] [4x4 double] [5x5 double]
>> result{1}, result{2}, result{3}
ans =
8 1 6
3 5 7
4 9 2
ans =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
ans =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Here's code that does what you want.
mydup = rand(5,2);
mycell = {mydup;mydup;rand(7,2);rand(3,2);rand(5,2)}
myNewCell = trimCell(mycell)
Where trimCell is the function below:
function myNewCell = trimCell(myCell)
exclude = false(size(myCell));
for iter = 1:size(myCell,1)
toCompare = myCell{iter};
comparisons = cellfun(#(x) all(size(x)==size(toCompare)) && myEquals(x, toCompare),myCell);
% comparisons has at least 1 true in it, because toCompare==toCompare
exclude(iter) = sum(comparisons)>1;
end
myNewCell = myCell(~exclude);
end
function boolValue = myEquals(x,y)
assert(all(size(x)==size(y)));
boolValue = true;
for iter = 1:size(x,1)
thisRow = all(sort(x(iter,:))==sort(y(iter,:)));
boolValue = boolValue && thisRow;
if ~boolValue
return
end
end
end
Basically, what this function does, is, for each matrix in the cell it checks first if the sizes are equal. If the sizes aren't equal, then we know the matrices aren't equal, even if we reorder the rows.
If they are the same size, then we need to check if they're equal after row reordering. That's accomplished by the function myEquals which goes through row by row and sorts the rows before comparing them. It exits with false on the first row it finds that is not equal after reordering.
Hope this helps,
Andrew

Variable-Length Array Addressing in Matlab

I'm sure there's an easy answer to this, but I'm not really sure what to search for. I have an array, M, of D dimensions, where D is constrained to be 1 <= D <= 5, and a vector of length D, X. I'd like to use D as an address within M and increment the value at that address, so if D were [1 2 3], I would want to increment M(1,2,3). I know I can do it like so:
if D == 1
M(X(1)) = M(X(1)) + 1;
end
if D == 2
M(X(1), X(2)) = M(X(1), X(2)) + 1;
end
But it's really ugly and I have to imagine there's a simpler, less clumsy way. Thanks!
You can use the function sub2ind to convert the address vector D to the corresponding dimensions in M. However, this would require that you store D as a cell and not a vector. The following example should help.
A=magic(5);%# just a test matrix
A=
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
d={3,4};%we need the element at row 3, column 4
indx=sub2ind(size(A),d{:});%# get the index corresponding to the subscript 3,4
A(indx)
ans=
20
You can also directly index it into the matrix A as A(sub2ind(size(A),d{:})), without having to create a separate variable.
You can also use num2cell to convert the vector to a cell. This might be a better option, as you might want to store D as a vector for other purposes. So the corresponding line becomes
indx=sub2ind(size(A),num2cell(d));