I have two structure and I'd like to have union of two matrices while the third row is added according to the common first two rows, the result is order-insensitive with respect to the first tow rows and duplicate values are avoided. i.e.
% struct1
row1 = [1 1 1 2 4 3];
col1 = [1 2 3 1 2 4];
att1 = [2 3 4 6 2 5];
% struct2
row2 = [2 2 1 3 3];
col2 = [1 2 3 1 4];
att2 = [1 0 1 1 5];
% result
resultRow = [1 1 1 2 2 3]
resultCol = [1 2 3 2 4 4]
resultAtt = [2 10 6 0 2 10]
I have the previously asked the intersection of two structure but it seems accumarray works for rows not matrices. Any help is appreciated.
Based on the solution to intersection part of this question, I think we can proceed as follows:
% struct1
row1 = [1 1 1 2 4 3];
col1 = [1 2 3 1 2 4];
att1 = [2 3 4 6 2 5];
% struct2
row2 = [2 2 1 3 3];
col2 = [1 2 3 1 4];
att2 = [1 0 1 1 5];
% sort in 2nd dimension to get row-column indexes insensitive for order
idx1 = sort([row1(:) col1(:)],2);
idx2 = sort([row2(:) col2(:)],2);
%find union
[idx,~,bins] = unique([idx1;idx2],'rows','stable');
att = accumarray(bins,[att1,att2]);
ResultUnion= [idx att]';
disp(ResultUnion)
and you get
ResultUnion =
1 1 1 2 3 2
1 2 3 4 4 2
2 10 6 2 10 0
Related
In Matlab I would like to do a sort on color values in a particular order.
Say for instance, Sort by Hue, then Sat, then Intensity (V). Or, by V, H then S.
Something like this:
% UNSORTED
A(:,:,1) = [1 1 1 1 1 2 2 2 1 1 1];
A(:,:,2) = [1 1 1 1 1 3 2 2 3 2 2];
A(:,:,3) = [3 1 4 3 2 1 2 1 1 2 1];
% RESULT
A(:,:,1) = [1 1 1 1 1 1 1 1 2 2 2]
A(:,:,2) = [1 1 1 1 1 2 2 3 2 2 3]
A(:,:,3) = [1 2 3 3 4 1 2 1 1 2 1]
I've struggled a day on this with no luck. Any help?
One method could be:
% UNSORTED
A(:,:,1) = [1 1 1 1 1 2 2 2 1 1 1];
A(:,:,2) = [1 1 1 1 1 3 2 2 3 2 2];
A(:,:,3) = [3 1 4 3 2 1 2 1 1 2 1];
for ii = 1:size(A,1)
A(ii,:,:) = reshape(sortrows(squeeze(A(ii,:,:)),[1:3]),[1,size(A,2),size(A,3)])
end
So we extract each 2D matrix, we use squeeze to delete the singleton dimension, then we use sortrows to sort each rows (with this priority 1->2->3). And finally we reshape this 2D matrix to restore the singleton dimension and obtain a 3D matrix.
Suppose the input is:
[1 2 3;
2 3 3;
3 4 3;
3 5 3;]
The expected output would be:
[1 2;
2 3;
3 4;
3 5;]
The reason to remove the third column is because all the elements in the third column is the same. Is there a default matlab function for this?
A(:,sum(abs(diff(A)))>0,1)
"Keep the columns where the difference is larger than zero"
Both the posted answers are incorrect. Test the edge cases where A only has 1 or 2 rows:
i.e:
A = [1 2 3];
or:
A = [1 2 3;
2 3 3];
diff and any need to be supplied with the correct dimension:
A = A(:,any(diff(A,1,1),1));
This outputs:
A = [1 2 3; 2 3 3];
EDU>> A(:,any(diff(A,1,1),1))
ans =
1 2
2 3
and
A = [1 2 3]
EDU>> A(:,any(diff(A,1,1),1))
ans =
Empty matrix: 1-by-0
Also, IMO this, semantically, makes the most sense:
A(:,all(bsxfun(#eq,A,A(1,:)),1)) = []
How about:
A =
1 2 3
2 3 3
3 4 3
3 5 3
B = A==repmat(A(1,:),size(A,1),1)
B =
1 1 1
0 0 1
0 0 1
0 0 1
C = sum(B) == size(A,1)
C =
0 0 1
A(:,C) =[]
A =
1 2
2 3
3 4
3 5
In one line:
A(:, sum(A==repmat(A(1,:),size(A,1),1)) == size(A,1)) = []
Creating a number pattern based on the length of array, the example is small just showing what it would look like if the array had a size of 5,6 or 7. (the actually length of arrays will be around 400,000)
How can I go about getting this numerical pattern. I was thinking it looked a little like Pascal's Triangle but the numbers are off.
I'm using Octave 3.8.1 which is like Matlab
example: If an array has the length of 5 the series would be
a1=[1 1 1;1 2 2;1 2 3;1 2 2;1 1 1]
a2=[1 1 1;2 2 1;3 2 1;2 2 1;1 1 1]
example: If an array has the length of 6 the series would be
a1=[1 1 1;1 2 2;1 2 3;1 2 3;1 2 2;1 1 1]
a2=[1 1 1;2 2 1;3 2 1;3 2 1;2 2 1;1 1 1]
example: If an array has the length of 7 the series would be
a1=[1 1 1 1;1 2 2 2;1 2 3 3;1 2 3 4;1 2 3 3;1 2 2 2;1 1 1 1]
a2=[1 1 1 1;2 2 2 1;3 3 2 1;4 3 2 1;3 3 2 1;2 2 2 1;1 1 1 1]
See image below:
This should be quite fast:
n = 9;
a1 = bsxfun(#min, min(1:n,n:-1:1).', 1:ceil(n/2));
a2 = a1(:,end:-1:1);
This does what you want:
n = 7;
a1 = cumsum(tril(ones(ceil(n/2))), 2);
a1 = a1([1:end end-mod(n,2):-1:1],:);
a2 = fliplr(a1);
A slighty different approach:
For m = ceil(n/2); the bsxfun can be substituted by
X = gallery('minij',m);
which is equal to:
X = bsxfun(#min, 1:m,(1:m).')
so you get a single block and you just need to concatenate the output.
a1 = [X; flipud(X)]
if n ~= 2*m; a1(m,:) = []; end %// clear one row if necessary
a2 = fliplr(a1)
for n = 6 you get
a1 =
1 1 1
1 2 2
1 2 3
1 2 3
1 2 2
1 1 1
and a2 accordingly mirrored. and for n = 5
a1 =
1 1 1
1 2 2
1 2 3
1 2 2
1 1 1
I need to transform a matrix:
X = [1 2; 3 4]
X = 1 2
3 4
to
X = [1 2; 1 2; 1 2; 3 4; 3 4; 3 4]
X = 1 2
1 2
1 2
3 4
3 4
3 4
and do this operation for a matrix with any number of rows.
How can I achieve this in MATLAB?
Here is a nice and easy way to do this using kron
kron(X,[1 1 1]')
this produces
1 2
1 2
1 2
3 4
3 4
3 4
I need some help in converting a 2X2 matrix to a 4X4 matrix in the following manner:
A = [2 6;
8 4]
should become:
B = [2 2 6 6;
2 2 6 6;
8 8 4 4;
8 8 4 4]
How would I do this?
In newer versions of MATLAB (R2015a and later) the easiest way to do this is using the repelem function:
B = repelem(A, 2, 2);
For older versions, a short alternative to the other (largely) indexing-based solutions is to use the functions kron and ones:
>> A = [2 6; 8 4];
>> B = kron(A, ones(2))
B =
2 2 6 6
2 2 6 6
8 8 4 4
8 8 4 4
Can be done even easier than Jason's solution:
B = A([1 1 2 2], :); % replicate the rows
B = B(:, [1 1 2 2]); % replicate the columns
Here's one more solution:
A = [2 6; 8 4];
B = A( ceil( 0.5:0.5:end ), ceil( 0.5:0.5:end ) );
which uses indexing to do everything and doesn't rely on the size or shape of A.
This works:
A = [2 6; 8 4];
[X,Y] = meshgrid(1:2);
[XI,YI] = meshgrid(0.5:0.5:2);
B = interp2(X,Y,A,XI,YI,'nearest');
This is just two-dimensional nearest-neighbor interpolation of A(x,y) from x,y ∈ {1,2} to x,y ∈ {0.5, 1, 1.5, 2}.
Edit: Springboarding off of Jason S and Martijn's solutions, I think this is probably the shortest and clearest solution:
A = [2 6; 8 4];
B = A([1 1 2 2], [1 1 2 2]);
A = [2 6; 8 4];
% arbitrary 2x2 input matrix
B = repmat(A,2,2);
% replicates rows & columns but not in the way you want
B = B([1 3 2 4], :);
% swaps rows 2 and 3
B = B(:, [1 3 2 4]);
% swaps columns 2 and 3, and you're done!
Here's a method based on simple indexing that works for an arbitrary matrix. We want each element to be expanded to an MxN submatrix:
A(repmat(1:end,[M 1]),repmat(1:end,[N 1]))
Example:
>> A=reshape(1:6,[2,3])
A =
1 3 5
2 4 6
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
ans =
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
1 1 1 1 3 3 3 3 5 5 5 5
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
2 2 2 2 4 4 4 4 6 6 6 6
To see how the method works, let's take a closer look at the indexing. We start with a simple row vector of consecutive numbers
>> m=3; 1:m
ans =
1 2 3
Next, we extend it to a matrix, by repeating it M times in the first dimension
>> M=4; I=repmat(1:m,[M 1])
I =
1 2 3
1 2 3
1 2 3
1 2 3
If we use a matrix to index an array, then the matrix elements are used consecutively in the standard Matlab order:
>> I(:)
ans =
1
1
1
1
2
2
2
2
3
3
3
3
Finally, when indexing an array, the 'end' keyword evaluates to the size of the array in the corresponding dimension. As a result, in the example the following are equivalent:
>> A(repmat(1:end,[3 1]),repmat(1:end,[4 1]))
>> A(repmat(1:2,[3 1]),repmat(1:3,[4 1]))
>> A(repmat([1 2],[3 1]),repmat([1 2 3],[4 1]))
>> A([1 2;1 2;1 2],[1 2 3;1 2 3;1 2 3;1 2 3])
>> A([1 1 1 2 2 2],[1 1 1 1 2 2 2 2 3 3 3 3])
There is a Reshape() function that allows you to do this...
For example:
reshape(array, [64, 16])
And you can find a great video tutorial here
Cheers