Combine 2 matrices - matlab

There is:
a = [1;2;3;4;5;6;7;8;9;10]; %(10x1 double)
b = [1;3;4;5;6;9]; %(6x1 double)
I hope to combine a and b. So my expected result is:
I think may be use conditional or first import zeros(10 2)? Could you help me?

Method 1: Conditional Checking
Checks if the values in the arrays match before filling the combined array. If they match both columns are filled. If they do not match the "NaN" undefined term is placed in the array. The variable Index that controls the scanning for array b is only incremented upon finding a match between both arrays.
%Method 1: Conditional%
a = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10];
b = [1; 3; 4; 5; 6; 9];
%Creating a result array of the same length as array "a"%
Combined_Array = zeros(length(a),2);
%Copying the first column into the result array "Combined_Array"%
for Row = 1: +1: length(a)
Combined_Array(Row,1) = a(Row,1);
end
%Padding the array "b" with zeroes to match the length of array "a"%
b = [b; zeros(length(a) - length(b),1)];
Index = 1;
for Row = 1: +1: length(a)
%If the values in arrays "a" and "b" do not match%
if a(Row,1) ~= b(Index,1)
Combined_Array(Row,2) = "NaN";
Index = Index - 1;
end
%If the values in arrays "a" and "b" match%
if a(Row,1) == b(Index,1)
Combined_Array(Row,2) = b(Index,1);
end
Index = Index + 1;
end
%Printing the result%
Combined_Array
Method 2: Concatenation and Filling Arrays
Fill in the arrays where the undefined term "NaN" is expected and concatenate the rest of the content accordingly. Using horzcat will concatenate columns together side by side. (vertcat concantates rows on top of one another)
%Method 2: Hard-Coded and Concatenation%
a = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10];
b = [1; 3; 4; 5; 6; 9];
b = [b(1); "NaN"; b(2:5);"NaN"; "NaN"; b(6); "NaN"];
Combined_Array = horzcat(a,b);

Related

Extract column data of table in a struct array

Summary / TLDR
How do I extract all rows of one table-column if the table is in a struct array and I want to combine alle struct-array-elements to one big matrix?
First Approch
I have a table (Values) with multiple columns and rows stored in a struct. Multiple of these structs are stored in an array (Data):
Data(1).Values = table([1; 2; 3; 4; 8], 'VariableNames', {'Rk'});
Data(2).Values = table([3; 6; 10; 8], 'VariableNames', {'Rk'});
Data(3).Values = table([2; 10; 11; 7], 'VariableNames', {'Rk'});
There are many more variables in the struct and also in the table, so it is just a simplified example. As you can see the height of the table can vary. I want to plot the columns Rk in a boxplot. So i need to create a matrix like this:
matrix = [1 1; 2 1; 3 1; 4 1; 8 1; 3 2; 6 2; 10 2; 8 2; 2 3; 10 3; 11 3; 7 3];
I use the following code to create the matrix:
matrix = zeros(0, 2);
for i=1:length(Data)
l = height(Data(1, i).Values(:, 'Rk'));
e = length(matrix) + 1;
% Reshape the data into an array
matrix((end+1):(end+l), 1) = table2array(Data(1, i).Values(:, 'Rk'));
% Creating the index of each data-row
matrix(e:end, 2) = i;
end
% Plot the boxplot
boxplot(matrix(:, 1), matrix(:, 2))
I really don't like this for-loop-version, especially because it becomes slow for big Data-Arrays and also because I don't know the size of matrix, so I can't reserve the space. Theoretically I could run through the whole data-array, counting the elements, initalizing the matrix-variable and then fill it.
Is there a more elegant version without a for-loop?
Second approach
I already tried another solution by changing the structure of the struct. Semantically, this really makes no sense, but this way I found a more elegant solution, creating the matrix-Variable without the problems of the first solution:
% Creating Data
Data(1).Values.Rk = [1; 2; 3; 4; 8];
Data(2).Values.Rk = [3; 6; 10; 8];
Data(3).Values.Rk = [2; 10; 11; 7];
% Reshape the data into an array
a = {cell2mat({Data.Values}).Rk};
b = vertcat(a{:});
% Creating the index of each data (b)-row
c = cumsum(cellfun('length', a(1, :)));
d = meshgrid(1:c(end), 1:length(c));
e = d>c';
f = sum(e);
% Plot the boxplot
boxplot(b, f);
Questions
I would apreciate a solution combining both approaches (having a table, no for-loop, no need of matrix-size-calculation) but:
I don't know how to extract the data of the table in a struct in an array.
I am asking myself if there is a more elegant solution creating the boxplot-indexes.
Whole code
%% Boxplot of Table
clear
% Creating Data
Data(1).Values = table([1; 2; 3; 4; 8], 'VariableNames', {'Rk'});
Data(2).Values = table([3; 6; 10; 8], 'VariableNames', {'Rk'});
Data(3).Values = table([2; 10; 11; 7], 'VariableNames', {'Rk'});
matrix = zeros(0, 2);
for i=1:length(Data)
l = height(Data(1, i).Values(:, 'Rk'));
e = length(matrix) + 1;
% Reshape the data into an array
matrix((end+1):(end+l), 1) = table2array(Data(1, i).Values(:, 'Rk'));
% Creating the index of each data
matrix(e:end, 2) = i;
end
boxplot(matrix(:, 1), matrix(:, 2));
%% Boxplot of Arrays
clear
% Creating Data
Data(1).Values.Rk = [1; 2; 3; 4; 8];
Data(2).Values.Rk = [3; 6; 10; 8];
Data(3).Values.Rk = [2; 10; 11; 7];
% Reshape the data into an array
a = {cell2mat({Data.Values}).Rk};
b = vertcat(a{:});
% Creating the index of each data (b)-row
c = cumsum(cellfun('length', a(1, :)));
d = meshgrid(1:c(end), 1:length(c));
e = d>c';
f = sum(e);
% Plot the boxplot
boxplot(b, f);
I have a partial answer if you are allowed to change the dimensions on your input table. If you transpose your input values, such that you have a row vector
Data(1).Values.Rk = [1; 2; 3; 4; 8]';
...
You can use the following commands to concatenate all the elements:
tmp = [Data.Values];
allvals = [tmp.Rk]'; %output is a column vector of your aggregated values
If you eliminate the Rk field (if it is not informative), you don't need the first step and can do the operation in one step.
If you aggregate the values into a column vector in this manner you now know the dimensions of the second column and can initialize that column before executing a for loop to populate the second column with a monotonically increasing index for each element of data.
I cannot think of a way to get the total number of elements and corresponding value for your box plot in the second column (without a for loop) unless you have the flexibility to add another field to your data structure (e.g. Data(1).nVals = 5, etc.), in which case you can get the total number of elements via sum([Data.nVals])

How can I turn Structure to n-dimensional matrix

I have 2 matrices.
First one is the names.
Names={'a','b','c'};
Second one is Numbers.
a=[1 3]; b=[4]; c=[2 4 5];
Then i have the structure names which is combination of names and numbers, and they are equal some random matrices with equal rows and columns.
For this case i have 6 combination (2*1*3) and it looks like =
a1.b4.c2=[7 8 9; 10 11 14];
a1.b4.c4=[2 4 5; 3 4 7];
a1.b4.c5=[3 2 11; 4 7 8];
a3.b4.c2=[1 1 1; 3 5 12];
a3.b4.c4=[2 7 9 ; 10 11 12];
a3.b4.c5=[4 2 7 ; 5 6 8];
I want to return this into n-dimensional matrix. In this case it is 5-dimensional which has to look like this;
(:,:,1,4,2)=[7 8 9; 10 11 14]; %%%% for a=1 b=4 c=2
(:,:,1,4,4)=[2 4 5; 3 4 7]; %%%% for a=1 b=4 c=4
(:,:,1,4,5)=[3 2 11; 4 7 8]; %%%% for a=1 b=4 c=5
(:,:,3,4,2)=[1 1 1; 3 5 12]; %%%% for a=3 b=4 c=2
(:,:,3,4,4)=[2 7 9 ; 10 11 12]; %%%% for a=3 b=4 c=4
(:,:,3,4,5)=[4 2 7 ; 5 6 8]; %%%% for a=3 b=4 c=5
I want to write a generalized code that helps me do this job for different numbers of names and numbers yet I couldnt do it. Hope you can help me! Thanks.
To get every combination of the possible numbers for each fields, use ndgrid.
[Numbers{1:3}] = ndgrid(a,b,c);
Having the numbered structures sitting in the workspace as you describe makes it messy to access them programmatically and you should avoid it if possible; however they can still be accessed using eval.
evalPattern = strjoin(strcat(Names,'%d'), '.'); % 'a%d.b%d.c%d'
firstNumbers = cellfun(#(n) n(1), Numbers); % [1 4 2]
firstElement = eval(sprintf(evalPattern,firstNumbers)); % returns the value of a1.b4.c2
result = nan([size(firstElement) size(Numbers{1}]);
for ii = 1:numel(Numbers{1})
iiNumbers = cellfun(#(n) n(ii), Numbers);
result(:,:,ii) = eval(sprintf(evalPattern,iiNumbers));
end
Ok, it took longer than I expected, but the following code should work for arbitrary number of names and numbers, given the following requirements:
At the moment, names are considered to be single characters - that could be tweaked by regexp or something like this.
All your ax.bx.cx.... can be stored in some superordinated structure by your application (beforehand).
Your struct always follows the presented order of ax.bx.cx..., and the matrix dimensions are equal.
So, the script is quite long and - I'm afraid - needs some explanation. Please just ask. The basic idea is to loop through the struct(s) as long as the particular "children" are still structs. That assures arbitrary "depth" of structs, i.e. number of names and numbers.
I expanded your data, so you see, that it also works for (a) additional names, (b) additional numbers, and (c) different matrix sizes. Of course, it also works on your original data.
Also, one doesn't need Names or Numbers in the beginning as these information are automatically extracted from the (has to be there superordinated) structure.
(Attention: Written in Octave. I tried to verify, that all functionality is available in Matlab, too. Please report any issues, if that's not the case. I will then refactor the code.)
% Structs given.
a1.b4.c2.d3 = ones(4, 4);
a1.b4.c4.d3 = ones(4, 4) * 2;
a1.b4.c5.d3 = ones(4, 4) * 3;
a1.b6.c2.d3 = ones(4, 4) * 4;
a1.b6.c4.d3 = ones(4, 4) * 5;
a1.b6.c5.d3 = ones(4, 4) * 6;
a2.b4.c2.d3 = ones(4, 4) * 7;
a2.b4.c4.d3 = ones(4, 4) * 8;
a2.b4.c5.d3 = ones(4, 4) * 9;
a2.b6.c2.d3 = ones(4, 4) * 10;
a2.b6.c4.d3 = ones(4, 4) * 11;
a2.b6.c5.d3 = ones(4, 4) * 12;
% REQUIREMENT: Store your structs in some superordinated struct.
super.a1 = a1;
super.a2 = a2;
% Initialize combined struct for names and numbers.
NamesNumbers = struct();
% Initialize Names cell array.
Names = {};
% Extract names and numbers from superordinated struct.
totalNames = 0;
totalNumbers = 1;
current = super;
while (isstruct(current))
fields = fieldnames(current);
totalNames = totalNames + 1;
totalNumbers = totalNumbers * numel(fields);
for iField = 1:numel(fields)
field = fields{iField};
name = field(1);
Names{totalNames} = name;
number = field(2:end);
if (isfield(NamesNumbers, name) == false)
NamesNumbers.(name) = str2num(number);
else
NamesNumbers.(name) = [NamesNumbers.(name) str2num(number)];
end
end
current = current.(fields{1});
if (isstruct(current) == false)
[nRows, nCols] = size(current);
end
end
% Extract all values from superordinated struct.
level = struct2cell(super);
while (isstruct([level{:}]))
level = struct2cell([level{:}]);
end
values = vertcat(level{:});
% Determine indices.
maxIdx = cellfun(#(x) max(x), struct2cell(NamesNumbers));
idx = zeros([totalNumbers, totalNames]);
factorProd = 1;
for iName = 1:totalNames
numbers = NamesNumbers.(Names{iName});
n = numel(numbers);
factorProd = factorProd * n;
inner = totalNumbers / factorProd;
resh = totalNumbers * n / factorProd;
outer = factorProd / n;
column = repmat(reshape(repmat(numbers, inner, 1), resh, 1), outer, 1);
START = (iName - 1) * totalNumbers + 1;
STOP = iName * totalNumbers;
idx(START:STOP) = column;
end
% Initialize output.
output = zeros([nRows nCols maxIdx']);
% Fill output with values.
for iIdx = 1:size(idx, 1)
temp = num2cell(idx(iIdx, :));
START = (iIdx - 1) * nRows + 1;
STOP = iIdx * nRows;
output(:, :, temp{:}) = values(START:STOP, :);
end

How to extract field based on field value

%Input structure
s.a=[1; 2; 1; 3; 4; 1; 2]
s.b=[4; 9; 7; 1; 0; 3; 8]
% output required
s.a=[1; 1; 1]
s.b=[4; 7; 3]
The actual structure contains many fields of long size. How to extract corresponding field values, when condition is put for field 'a' (when a==1).
Try this and adapt to the other fields:
s.b(s.a==1)
To do it for all fields in s except a and collect the results in a struct t you can use a loop:
t = struct()
fn = fieldnames(s);
for k=1:numel(fn)
t.(fn{k}) = s.(fn{k})(s.a==1);
end

removing missing elements from a vector

I have a vector B=[1; 2; 1; 2; 3; 5; 6; 8; 9; 10]
where the elements a=[4 7] are missing.
I would like to map B to a "continuous" vector like
B_map=[1; 2; 1; 2; 3; 4; 5; 6; 7; 8]
removing the "missing" elements (4 7) and "scaling" the rest accordingly..
my problem is that depending on the number of missing elemenst (in this case 2) I have to scale the vector B of different amounts...
I think I figured it out...
a = sort(a);
B_map = B;
for i = 1:numel(a)
clear id_sub
id_sub = find(B >= a(i));
B_map(id_sub) = B_map(id_sub)-1;
end

How to do a pairwise interchange of rows in Matlab?

I have a sequence in an matrix (computed from sortrows function in Matlab). Say the matrix looks something like this after computing:
A = [5; 3; 4; 1; 2];
[b, c] = size(A)
In lieu of performing permutations on the sequence in A, I would like to peform a pairwise interchange of the cells, so the performance runs better, even though the results won't be exact (it will be very close to answer though). I want the rows to look somewhat like this in the end =>
A1 = [5; 4; 3; 2; 1];
A2 = [4; 5; 3; 1; 2];
A3 = [4; 3; 5; 2; 1];
A4 = [3; 4; 5; 1; 2];
Now, the catch is that the matrix will contain as little or as much elements (it will vary). Matrix 'A' is just an example. How do I perform [b-1] pairwise interchanges on A (or any other matrix)?
A = [5; 3; 4; 1; 2];
swapIndexLeft = [1,2,3,4,5];
swapIndexRight = [2,3,4,5,1];
%// make sure the dimension of indices agree
assert(numel(swapIndexLeft) == numel(swapIndexRight))
%// ... and values do not exceed dimensions of the vector A
assert(max(swapIndexLeft)<=numel(A) )
assert(max(swapIndexRight)<=numel(A) )
%// swap iteratively
for ii = 1:numel(swapIndexLeft)
temp = A( swapIndexLeft(ii) );
A( swapIndexLeft(ii) ) = A( swapIndexRight(ii) );
A( swapIndexRight(ii) ) = temp;
%// now you have an array where the element swapIndexLeft(ii)
%// has been swapped with swapIndexRight(ii)
%// do your calculations here
end