A table with 2 columns where one column increases sequentially while the other column displaying the same number till a limit is reached - matlab

I have been trying to write a code where the users enters two numbers in order to get 2 columns. It is very hard to explain by words what I am trying to achieve so here is an example:
If the user inputs a = 1 and b = 1, the following table should be created:
ans =
1 1
If the user inputs a = 2 and b = 2:
ans =
1 1
1 2
2 1
2 2
If the user inputs a = 2 and b = 5:
ans =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
For other values of a and b, the matrix should be constructed according to the above shown sequence.

This can be achieved straight-forward by the use of repelem and repmat:
[repelem((1:a).',b),repmat((1:b).',a,1)]
A more elegant way is using meshgrid and reshape it after:
[A,B] = meshgrid(1:a,1:b);
[A(:),B(:)]
Let's create an anonymous function and test the first approach:
>> fun = #(a,b) [repelem((1:a).',b),repmat((1:b).',a,1)];
>> fun(1,1)
ans =
1 1
>> fun(2,2)
ans =
1 1
1 2
2 1
2 2
>> fun(2,5)
ans =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5

Here is an alternative way
for example a = 2 and b = 5
A(1:b*a,1) = reshape(mtimes((1:a).',ones(1,b)).',1,b*a)
A(1:b*a,2) = reshape(mtimes((1:b).',ones(1,a)),1,b*a)
A =
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
There is just one logic, in the code below you define a matrix of row size and a and column size b
>> mtimes((1:a).',ones(1,b))
ans =
1 1 1 1 1
2 2 2 2 2
and the next step simply reshapes the matrix column wise for a and row wise for b by taking a transpose
A(1:b*a,1) = reshape(mtimes((1:a).',ones(1,b)).',1,b*a)
A(1:b*a,2) = reshape(mtimes((1:b).',ones(1,a)),1,b*a)

Related

MATLAB: Splitting a matrix based on multiple values

I'm dealing with matrices of this format:
M =
1 1 3
1 1 1
1 2 2
1 2 1
1 2 2
2 1 5
2 1 1
2 2 3
2 2 4
2 2 2
...
What I want to do is extract sub matrices where the values in the first and second column can be grouped such that:
M1 =
1 1 3
1 1 1
M2 =
1 2 2
1 2 1
1 2 2
M3 =
2 1 5
2 1 1
...
I have been trying to think hard about how to index the matrix for this and I have a matrix available:
I =
1 1
1 2
2 1
2 2
...
that I could use for indexing. I was wondering if I could use it but I'm not 100% sure how. I don't want to use a for loop since the matrixes can be rather large and the order of complexity can become very large.
Thank you for reading!
This is easily done with unique and accumarray:
M = [ 1 1 3
1 1 1
1 2 2
1 2 1
1 2 2
2 1 5
2 1 1
2 2 3
2 2 4
2 2 2 ]; %// data
[~, ~, u] = unique(M(:,1:2), 'rows'); %// unique labels of rows based on columns 1 and 2
M_split = accumarray(u(:), (1:size(M,1)).', [], #(x){M(sort(x),:)}); %'// group rows
% // based on labels
This gives a cell array containing the partial matrices. In your example,
M_split{1} =
1 1 3
1 1 1
M_split{2} =
1 2 2
1 2 1
1 2 2
M_split{3} =
2 1 5
2 1 1
M_split{4} =
2 2 3
2 2 4
2 2 2

Create a multidimensional array following a pattern

I am making a 3 dimensional array, using matlab, that progresses according to a pattern. Athough I could write out the Array manually I am sure there is a quicker way to do it.
multiArray = cat(3,...
[1+randn(4,3); 1*randn(4,3)],...
[2+randn(4,3); 2*randn(4,3)],...
[3+randn(4,3); 3*randn(4,3)]);
If I want to make the above array to be 8x3x25 then the last line would be
[25+randn(4,3); 25*randn(4,3)]
But how can I make such an array without going through all the tedious intervening steps?
While mikkola basically got the solution, there is no need to shift dimensions at the end.
s=[4,3,25];
it=reshape(1:s(3),1,1,[]);
out = [bsxfun(#plus , it, randn(s));...
bsxfun(#times, it, randn(s))];
Here's a possible way using bsxfun.
%// 25 x 4 x 3 with elements for i + randn(4,3)
P = bsxfun(#plus, (1:25)', randn(25,4,3));
%// 25 x 4 x 3 with elements for i * randn(4,3)
T = bsxfun(#times, (1:25)', randn(25,4,3));
%// Concatenate and shift dimensions to get desired size output
multiArray = shiftdim([P T], 1);
If you don't mind taking things to 4D for efficiency purposes -
N = 25; %// Number of 3D slices
out = randn(4,2,3,N);
out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
To legitimize the solution, let's start off with an input of A = randn(8,3,N) and initialize the output out with it. Also, let's take number of 3D slices as a small number, so say N = 3.
Thus,
>> N = 3;
A = randn(8,3,N);
out = reshape(A,[4 2 3 N]); %// This replaces "out = randn(4,2,3,N)"
Next up, we run the code that will change out -
>> out(:,1,:,:) = bsxfun(#plus,permute(1:N,[1 4 3 2]),out(:,1,:,:));
out(:,2,:,:) = bsxfun(#times,permute(1:N,[1 4 3 2]),out(:,2,:,:));
out = reshape(out,8,3,N);
Now, start validating per 3D slice -
>> out(1:4,:,1) - A(1:4,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(1:4,:,2) - A(1:4,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(1:4,:,3) - A(1:4,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3
>> out(5:end,:,1)./A(5:end,:,1)
ans =
1 1 1
1 1 1
1 1 1
1 1 1
>> out(5:end,:,2)./A(5:end,:,2)
ans =
2 2 2
2 2 2
2 2 2
2 2 2
>> out(5:end,:,3)./A(5:end,:,3)
ans =
3 3 3
3 3 3
3 3 3
3 3 3

Creating an index matrix depending on Reference matrix and matrix of Data matlab

given matrix A of size 6 by 6 contain blocks of numbers,each block of size 2 by 2, and outher reference matrix R of size 2 by 12 also contain blocks of numbers, each block of size 2 by 2. the perpse of the whole process is to form a new matrix, called the Index matrix, contain index's that refer to the position of the blocks within the matrix A based on the order of the blocks within the reference matrix R. and here is an exemple
matrix A:
A =[1 1 2 2 3 3;
1 1 2 2 3 3;
1 1 3 3 4 4;
1 1 3 3 4 4;
4 4 5 5 6 6;
4 4 5 5 6 6 ]
matrix R:
R=[1 1 2 2 3 3 4 4 5 5 6 6;
1 1 2 2 3 3 4 4 5 5 6 6 ]
the new matrix is:
Index =[1 2 3;
1 3 4;
4 5 6]
any ideas ?
With my favourite three guys - bsxfun, permute, reshape for an efficient and generic solution -
blksz = 2; %// blocksize
num_rowblksA = size(A,1)/blksz; %// number of blocks along rows in A
%// Create blksz x blksz sized blocks for A and B
A1 = reshape(permute(reshape(A,blksz,num_rowblksA,[]),[1 3 2]),blksz^2,[])
R1 = reshape(R,blksz^2,1,[])
%// Find the matches with "bsxfun(#eq" and corresponding indices
[valid,idx] = max(all(bsxfun(#eq,A1,R1),1),[],3)
%// Or with PDIST2:
%// [valid,idx] = max(pdist2(A1.',reshape(R,blksz^2,[]).')==0,[],2)
idx(~valid) = 0
%// Reshape the indices to the shapes of blocked shapes in A
Index = reshape(idx,[],num_rowblksA).'
Sample run with more random inputs -
>> A
A =
2 1 1 2
1 2 2 1
1 1 1 1
2 2 2 2
1 2 2 1
1 2 1 1
>> R
R =
2 1 1 1 1 2 2 2 1 1 1 1
2 1 2 1 1 2 2 1 2 2 2 1
>> Index
Index =
0 0
5 5
3 0

Find column vectors contained in B but not in A - MATLAB

I have matrix A of size 10x100 and matrix B with size 10x200.
How to find the column vectors contained in B but not in A? ( A and B do not have the same number of columns)
to elaborate #Cheery's comment with an example.
A=[1;4];
B=[1 2 4;4 5 6];
C=setdiff(B',A','rows')';
more details see http://www.mathworks.com/help/matlab/ref/setdiff.html
You can also use bsxfun here -
Bout = B(:,all(any(bsxfun(#ne,B,permute(A,[1 3 2])),1),3))
Sample run -
A =
2 2 2 2 2
2 2 1 1 1
1 1 2 1 3
B =
3 2 3 2 1 2 2
3 1 3 1 1 1 3
2 3 1 2 1 2 3
Bout =
3 3 1 2
3 3 1 3
2 1 1 3

Quick way to sort an array with respect to row sum in Matlab

Here's a small example of what I want. Given the following array:
1 1 2
2 2 1
1 1 1
1 1 6
Sorted (row sum is shown in parenthesis):
1 1 6 (8)
2 2 1 (5)
1 1 2 (4)
1 1 1 (3)
Is there a quick way to achieve this in Matlab?
Since sort returns the indexes in order as well as the sorted matrix, you can use these indices to access the original data -- try this:
% some data
A = [
1 1 2;
2 2 1;
1 1 1;
1 1 6;
];
% compute the row totals
row_totals = sum(A,2);
% sort the row totals (descending order)
[sorted, row_ids] = sort(row_totals, 'descend');
% and display the original data in that order (concatenated with the sums)
disp([A(row_ids,:), row_totals(row_ids)])
>>>
1 1 6 8
2 2 1 5
1 1 2 4
1 1 1 3
The ugliest one-liner I could come up with:
>> subsref( sortrows( [sum(A,2) A], -1 ), struct('type','()','subs',{{':',1+(1:size(A,2))}}) )
ans =
1 1 6
2 2 1
1 1 2
1 1 1
Disclaimer: I don't think anyone should write this kind of code, but it's a nice practice to keep your Matlab's skills sharp.
Just do something very simple like follows
temp = [1 1 2
2 2 1
1 1 1
1 1 6];
rowSums = sum(temp,2);
[~,idx] = sort(rowSums,'descend');
output = [temp(idx,:),rowSums(idx)];
EDIT
Changed the above code to make sure the sum is appended to the last column. I did not notice that this was a requirement when I read the question initially.
I leave it for you to judge if this is uglier than #Shai's:
fliplr(diff([sortrows(fliplr(-cumsum(A,2))) zeros(size(A,1),1) ],1,2))
Let's do some matrix multiplication
>> sortrows([sum(A,2) A], -1)*[zeros(1,size(A,2)); eye(size(A,2))]
returns
ans =
1 1 6
2 2 1
1 1 2
1 1 1