Convert a matrix to a vector using a spiral path - matlab

I have seen until now that when someone wants to read the elements of a matrix using a spiral one by one they always mean starting outwards and slowly moving to the center using an MxM matrix. How would we do the opposite, start from a random point inside the matrix and using a "spiraling" path to read all the elements.
I am doing the tests using Matlab.
Example.
mat=
1 2 3
4 5 6
7 8 9
If lets say we were to start from mat(3,1) spiraling clockwise then we would have
vec=
7, 8, 4, 5, 6, 9, 1, 2, 3
and if we started from mat(2,2) then
vec=
5, 6, 9, 8, 7, 4, 1, 2, 3

One possible approach:
mat = [1 2 3; 4 5 6; 7 8 9];
M = length(mat); % Assuming mat is always MxM
r = 3;
c = 1;
temp = spiral(2 * M - 1);
temp = temp(M - r + 1:end - r + 1, M - c + 1:end - c + 1);
[~, idx] = sort(temp(:));
vec = mat(idx).'
Result running with r = 3 and c = 1
vec =
7 8 4 5 6 9 1 2 3
Result running with r = 2 and c = 2
vec =
5 6 9 8 7 4 1 2 3

Related

Finding Positions of Repeating Elements in a Matrix in Matlab

I have a vector A = [ 1 1 1 2 3 3 3 2 2 1 1 1 1 3 3 3 ].
I want to find the positions of every element and store this in its own matrix.
To be more specific, I want to find the position of every elements for each set of elements, in a n by m matrix (where m would be the type of element, and n would be the number of elements found in vector A).
So, for example, assuming there are only values 1, 2, and 3 in vector A, the first column of my matrix would be for values that are 1, and would read off (1, 2, 3, 10, 11, 12, 13) and the second column, for values of 2, would read off (4, 8, 9) and the third column, for values of 3, would read off (5, 6, 7, 14, 15, 16).
This one liner works as expected:
B = accumarray(A', 1:length(A), [], #(x) {sort(x)})
B is a cell array where B{i} contains the sorted list of indices where i is located.
This could be one approach -
%// For each element create a pair: [R,C], where the first element R would
%// represent its index position in input array and C would be their uniqueness
[R,C] = find(bsxfun(#eq,A(:),unique(A(:).'))) %//'
%// Find lengths of each unique group
lens = diff([0 ; find(diff(C)) ; numel(C)])
%// Store each element into groups based on the uniqueness and whose
%// values would be the index positions i.e. taken from R
out = mat2cell(R(:).',1,lens)
Sample run for given input -
>> A
A =
1 1 1 2 3 3 3 2 2 ...
1 1 1 1 3 3 3
>> celldisp(out)
out{1} =
1 2 3 10 11 12 13
out{2} =
4 8 9
out{3} =
5 6 7 14 15 16
Similar to Divakar's answer but with sort
[out,i] = sort(A);
out1 = diff(find([1,diff(out)]));
out2 = [out1,numel(A)-sum(out1(:))];
out3 = mat2cell(i,1,out2);
Results:
A = [ 1 1 1 2 3 3 3 2 2 1 1 1 1 3 3 3 ]; %// input
>> celldisp(out3)
out3{1} =
1 2 3 10 11 12 13
out3{2} =
4 8 9
out3{3} =
5 6 7 14 15 16

Outer product in Matlab?

How to turn two vectors into a matrix of all combinations of their elements?
For example, vectors
>> A=[1;2;3]
A =
1
2
3
>> B=[4;5;6]
B =
4
5
6
Should be turned to
[1, 4; 1, 5; 1, 6; 2, 4; 2, 5; 2, 6; 3, 4; 3, 5; 3, 6]
ans =
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
I'm sure there is a simpler way of doing this but... meshgrid will get you close and you just need to perform some array manipulation to get your result:
[BA, BB] = meshgrid(A,B);
[BA(:) BB(:)]
An order of magnitude slower than meshgrid, but just to show you a different method:
[kron(A,ones(numel(B),1)), kron(ones(numel(A),1), B)];

How do I Combine two equal sized vectors element wise in MatLab?

I have two vectors:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
That I need to combine together element wise. Meaning that I need the first element of vector a, then the first element of vector b, second of a, second of b, and so forth until I get the following:
combined = [1 2 3 4 5 6 7 8 9 10]
How do I do this within MatLab?
Edit
I ran a test of the top three answers (Josh, Marc, & Kronos) and compared the time it took to run them. I ran each 100 times after doing a 10 iteration warmup. The vectors created were exactly the same size in length (16e+6) and were random values ranging from 1 to 100:
Test Results
Test: Total Time (100 runs): Avg Time Per Exec:
Josh B 21.3687 0.2137
Marc C 21.4273 0.2143
Kronos 31.1897 0.3119
It appears that both Josh's and Marc's solutions are similar in execution time.
a = [1 3 5 7 9];
b = [2 4 6 8 10];
temp = [a; b];
combined = temp(:)';
This can be done by the following:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
combinedSize = size(a, 2) * 2;
combined(1:2:combinedSize) = a;
combined(2:2:combinedSize) = b;
This is obviously assuming that your vectors are exactly the same size. If by chance you want to merge two vectors that are not the same size then you can do the following:
combinedSize = max(size(a, 2), size(b, 2)) * 2;
combined = NaN(1,combinedSize);
combined(1:2:size(a,2)*2) = a;
combined(2:2:size(b,2)*2) = b;
This will place a NaN for the remaining elements of the smaller vector. For example, given the following sample vectors:
a = [1 3 5 7 9 11];
b = [2 4 6 8];
will result in the combined vector:
combined =
1 2 3 4 5 6 7 8 9 NaN 11 NaN
Place the vectors below eachother in a matrix and use reshape. For example:
>> A=[1 2 3]
A =
1 2 3
>> B=[4 5 6]
B =
4 5 6
>> C=reshape([A;B],1,size(A,2)+size(B,2))
C =
1 4 2 5 3 6
It's straightforward to generalize to more than 2 vectors.
You can also give a try to looping, for example:
a=[1 2 3 4 5];
b=[11 12 13 14 15];
for i = 1:N
{
if (i%2==0)
{ c[i] = b[i]; }
else
{ c[i] = a[i]; }
This shall work!
All the answers above only work if the two vectors have the same number of elements. The following will work even if they have different number of elements:
>>
A = [1 3 5];
B = [2 4 6 7 8];
C = [1 3 5 7 8];
D = [2 4 6];
AB = nan(1,2*max(numel(A),numel(B)));
CD = nan(1,2*max(numel(C),numel(D)));
AB(2*(1:length(A))) = A;
AB(1+2*(1:length(B))) = B;
CD(2*(1:length(C))) = C;
CD(1+2*(1:length(D))) = D;
>>
AB = AB(~isnan(AB))
CD = CD(~isnan(CD))
The result would be:
AB =
1 2 3 4 5 6 7 8
CD =
1 2 3 4 5 6 7 8

Expand a matrix with polynomials

Say I have a matrix A with 3 columns c1, c2 and c3.
1 2 9
3 0 7
3 1 4
And I want a new matrix of dimension (3x3n) in which the first column is c1, the second column is c1^2, the n column is c1^n, the n+1 column is c2, the n+2 column is c2^2 and so on. Is there a quickly way to do this in MATLAB?
Combining PERMUTE, BSXFUN, and RESHAPE, you can do this quite easily such that it works for any size of A. I have separated the instructions for clarity, you can combine them into one line if you want.
n = 2;
A = [1 2 9; 3 0 7; 3 1 4];
[r,c] = size(A);
%# reshape A into a r-by-1-by-c array
A = permute(A,[1 3 2]);
%# create a r-by-n-by-c array with the powers
A = bsxfun(#power,A,1:n);
%# reshape such that we get a r-by-n*c array
A = reshape(A,r,[])
A =
1 1 2 4 9 81
3 9 0 0 7 49
3 9 1 1 4 16
Try the following (don't have access to Matlab right now), it should work
A = [1 2 9; 3 0 7; 3 1 4];
B = [];
for i=1:n
B = [B A.^i];
end
B = [B(:,1:3:end) B(:,2:3:end) B(:,3:3:end)];
More memory efficient routine:
A = [1 2 9; 3 0 7; 3 1 4];
B = zeros(3,3*n);
for i=1:n
B(3*(i-1)+1:3*(i-1)+3,:) = A.^i;
end
B = [B(:,1:3:end) B(:,2:3:end) B(:,3:3:end)];
Here is one solution:
n = 4;
A = [1 2 9; 3 0 7; 3 1 4];
Soln = [repmat(A(:, 1), 1, n).^(repmat(1:n, 3, 1)), ...
repmat(A(:, 2), 1, n).^(repmat(1:n, 3, 1)), ...
repmat(A(:, 3), 1, n).^(repmat(1:n, 3, 1))];

GROUP BY in MATLAB

I want to do what SQL's GROUP BY does in MATLAB. For example,
M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ]
SQL: SELECT MAX(c1), c2 FROM M(c1, c2) GROUP BY 2
Result = [
3, 5;
2, 6;
1, 7]
How can I do this in Matlab?
grpstats in the Statistics Toolbox can do this:
>> [grpstats(M(:,1), M(:,2), {'max'}) unique(M(:,2))]
ans =
3 5
2 6
1 7
If you don't mind doing some preprocessing to get the order (or if the first column is nicely built from 1 to n), you can do it like this:
accumarray([1 2 3 1]',[11 12 13 14]',[],#max)
This will give:
14
12
13
Or in your case:
accumarray(M(:,1),M(:,2),[],#max)
Note the order. The second number for example, will correspond to M(:,1) == 2
I think there is a simple solution to this.
Here is what I tested on Matlab and it worked:
>> M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ];
>> grpstats(M,M(:,2),{'max'})
ans =
3 5
2 6
1 7