Matlab 2D-Array indexing and replacing - matlab

Given array Array_in of size m*n and R of size s*2. Each row in array R corresponds to the starting and ending values of the first column of Array_in and the corresponding column elements in Array_in i.e from Array_in(:,2:end) should not be changed and all remaining elements are replaced by NaN. The first column of the output Array_out is same as the Array_in. The number of rows of array R changes. In the following example the number of rows are assumed to be 2.
Array_in = [0 0.1;1 0.8;2 0.5;3 0.2;4 0.3;5 0.6;6 0.8;7 1;8 1.2;9 1;10 0.1];
R = [2 3;6 9];
R 1st row: should be considered as 2:3 = [2 3];
R 2nd row: as 6:9 = [6 7 8 9]; all the rows i.e [2 3 6 7 8 9] should be retained and
and the expected output is:
Array_out = [0 NaN;1 NaN;2 0.5;3 0.2;4 NaN;5 NaN;6 0.8;7 1;8 1.2;9 1;10 NaN];
How can this be done?

ind = ~any( bsxfun(#ge, Array_in(:,1).', R(:,1)) & ...
bsxfun(#le, Array_in(:,1).', R(:,2)) );
Array_out = Array_in;
Array_out(ind,2:end) = NaN;

Try this -
t1 = bsxfun(#times,1:size(Array_in,1),ones(size(R,1),1))
t2 = bsxfun(#ge,t1,R(:,1)) & bsxfun(#le,t1,R(:,2))
ind = ~any(bsxfun(#eq,Array_in(:,1),find(any(t2))),2)
Array_out = Array_in;
Array_out(ind,2:end)=NaN

Related

How to get all unique values in a cell array of matrices?

I want to get all unique values in A, where A is a cell array of matrices of different shapes and sizes:
A = {[], 1, [2 3], [4 5; 6 7]};
U = [];
for ii = 1: numel(A)
a = A{ii};
U = [U; a(:)];
end
U = unique(U);
That returns:
U =
1 2 3 4 5 6 7
If all elements in A where row vectors, I could use [A{:}] like:
U = unique([A{1:3}]);
That returns:
U =
1 2 3
But in my case it throws an exception:
Error using horzcat
Dimensions of matrices being concatenated are not
consistent.
So how can I avoid that for-loop?
You can use cellfun to reshape all elements in the cell.
U = unique(cell2mat(cellfun(#(x)reshape(x,1,numel(x)),A, 'UniformOutput', false)));
or avoiding the reshapewith
U = unique(cell2mat(cellfun(#(x)x(:).',A, 'UniformOutput', false)));
We can go this way:
A = {[], 1, [2 3], [2 0; 4 5; 6 7]};
AA = cellfun( #(x) unique(x(:)), A, 'UniformOutput' , false)
res = unique(cat(1, AA{:}))
First of all create unique array for each cell - it let us avoid converting all the cells to numeric just only unique values.
Lets convert cell array to one numeric array - cat(1, AA{:}) .
Find unique values through this resulting array.

Get the first four minimum values in a matrix

I have a matrix:
X =
0 81 13 15 100 2
11 0 6 10 200 8
19 22 0 20 300 23
I want to get the first four minimal values in the whole array X with the indices of each value in the array. For example I should get vector v = [2 6 8 10] and the index of each value in X.
Also, I want to ignore the zero values when the row number equals the column number.
I have tried to use the min and sort functions, but I am not sure how to do it.
I would suggest the following
X2 = X;
X2(~~eye(size(X2))) = inf; %// or X2(logical(eye(size(X2)))) = inf
[val, idx] = sort(X2(:));
result = val(1:4);
[idxRow, idxCol] = ind2sub(size(X), idx(1:4));
Use:
vals = sort(X(~eye(size(X)))); %takes non diagonal values and sort the result
res = vals(1:4) %finds the first 4 elements (which are the smallest)
[row, col] = find(ismember(X,res)); %gets the indices
result:
res = [2; 6; 8; 10]
By The way, if you don't want to ignore all the diagonal values, only the zero ones, use:
vals = sort(X(~eye(size(X)) | (eye(size(X)) & X~=0)));
Sort all but the ones on the diagonal and then find the indices of the ones which are smaller than or equal to the 4th element of sorted array and not on the diagonal:
T=sort(X(~eye(size(X))));
v = T(1:4);
[I,J] = find(X <= v(end) & ~eye(size(X)));
Just want to add to drorco's perfect answer how to find indexes of this first elements:
indexes = arrayfun( #(a) find(X==a), res);
or if you want to get numbers of rows and columns:
[r,c] = arrayfun( #(a) find(X==a), res);
P.S. it works perfectly if all elements except zeros in X are unique.

Find row-wise combinations of a 2 dimensional matrix

I have a matrix:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
I want to find all row-wise combinations of X. i.e.
A(1) = [2, 6, 1; 3, 8, 1; 4, 7, 1]
A(2) = [2, 6, 1; 3, 8, 1; 6, 2, 1]
:
:
:
Here's what I've tried:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3
[m, n] = size(X);
comb = combnk(1:m, p);
[s, t] = size(comb);
c = [X(comb(:,1), :, :) X(comb(:,2), :, :) X(comb(:,3), :, :)];
This gives me a matrix like:
c = 2 6 1 3 8 1 4 7 1
2 6 1 3 8 1 6 2 1
2 6 1 3 8 1 6 4 1
I want to apply the concatenate matrix option to obtain c to make it dynamic depending on value of p but I'm not sure how to use it. I don't want to use For loops. Please help me out.
This is fully vectorized, so it should be fast:
n = 3; %// number of rows to pick each time
ind = reshape(nchoosek(1:size(X,1), n).', [], 1); %'// indices of combinations
A = permute(reshape(X(ind,:).', size(X,2), n, []), [2 1 3]);
The result is
A(:,:,1)
ans =
2 6 1
3 8 1
4 7 1
A(:,:,2)
ans =
2 6 1
3 8 1
6 2 1
etc.
Should you need the result in the form of a cell array, you can convert A from 3D-array to cell array this way:
A = mat2cell(A, size(A,1), size(A,2), ones(1,size(A,3)));
Your thinking is pretty close. This code does the job. I put comments in code, which should be easy to read.
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3;
%// List all combinations choosing 3 out of 1:8.
v = nchoosek(1:size(X,1), p);
%// Use each row of v to create the matrices, and put the results in an cell array.
%// This is the A matrix in your question.
A = arrayfun(#(k)X(v(k,:), :), 1:size(v,1), 'UniformOutput', false);
%// And you can concatenate A vertically to get c.
flatA = cellfun(#(x)reshape(x, 1, []), A, 'UniformOutput', false);
c = vertcat(flatA{:});
PS: From my understanding I thought the result you wanted was A, which is an easy to use cell array. But I added an extra step to get c exactly as in your question just in case.
Disclaimer: arrayfun and cellfun are pretty much equivalent to for loop in terms of performance.
You can do it using reshape and a bunch of transposes since Matlab is column-major ordered:
c = reshape(X(comb',:)',9,[])'
or if you want a 3D matrix:
A = permute(reshape(X(comb',:)',3,3,[])', [2,1,3])

Find part of vector in another vector matlab

I would like to know if there is an easy way to find the indices of a vector in another vector in matlab:
a = [1 2 3 5 7 10 2 3 6 8 7 5 2 4 7 2 3]
b = [2 3]
So how to get the indices of a when comparing it with b (index of first element is needed)
In this case:
ans = [2 7 16]
Thanks in advance
find(a(1:end-1) == b(1) & a(2:end) == b(2) == 1)
You can re-purpose strfind by converting the elements of both vectors to byte arrays (uint8) with typecast:
bytesPerEl = numel(typecast(a(1),'uint8'));
byteLocs = strfind(char(typecast(a,'uint8')),char(typecast(b,'uint8')));
locsb = (byteLocs-1)/bytesPerEl + 1
locsb =
2 7 16
Just make sure a and b are of the same type. Also note that this works for 1D vectors, not matrixes or higher dimensional arrays.
General approach with length of b arbitrary (not necessarily 2 as in the example), and avoiding the use of strings:
match1 = bsxfun(#eq, a(:), b(:).'); %'// now we just need to make the diagonals
%// horizontal (in order to apply "all" row-wise). For that we'll use indices
%// ind, ind1, ind2
ind = reshape(1:numel(match1), numel(a), numel(b));
ind1 = nonzeros(tril(ind)); %// source indices
ind2 = sort(nonzeros(tril(flipud(ind)))); %// destination indices
match2 = zeros(size(match1));
match2(ind2) = match1(ind1); %// diagonals have become horizontal
result = find(all(match2.'));

MATLAB: dividing a cell's members into smaller cells according to a vector

I have a cell array of size 1*n (X=cell(1, n)). every cell in this cell array(X), has a different size. So, to be clear, here is an example:
X = {X1, X2, X3} (n=3)
X1 = [1 3 5 9]
X2 = [1 2 3 6 7]
X3 = [1 7 8 9]
I have a vector with length of m. for example:
Y = [0 3 6 9] (m=4)
I want to divide cells in my cell array according to this vector in this way:
X1-1=[1] (because 1>=Y(1) & 1<Y(2)), X1-2=[3 5] (because 3 and 5>=Y(2) & 1<Y(3)), X1-3=[9] (because 9>=Y(3) & 9<Y(4))
and so on for X2 and X3...
and finally I have:
Z = {X1-1 X2-1 X3-1
X1-2 X2-2 X3-2
X1-3 X2-3 X3-3}
Here is my code with for-loops:
Z = cell(size(X,2), size(Y,2));
for i = 1:size(X,2)
T = cell2mat(X(i));
for j = 1:size(Y,2)-1
idx = (T > Y(j) & T < Y(j+1));
Z{i,j} = {T(idx)'};
end
end
Z = cellfun(#(z) cell2mat(z), Z, 'UniformOutput', false);
I want to get the same results without using for-loops. Any vectorization ideas?
You can replace the two for loops with one cellfun and one arrayfun. Not necessarily faster, though:
Z = cellfun(#(Xi) arrayfun(#(k) Xi(Y(k)<=Xi&Xi<Y(k+1)), 1:numel(Y)-1, 'uni', 0).', X, 'uni', 0);
The desired results are stored in Z{1}{1} (corresponding to your X1-1), Z{1}{2} (corresponding to X1-2), etc.
Example: I'm using your data but changing Y to [0 3 6 9.1] (note that with Y = [0 3 6 9] the X1-3 in your example is not correct):
>> Z{1}{1}
ans =
1
>> Z{1}{2}
ans =
3 5
>> Z{1}{3}
ans =
9
>> Z{2}{1}
ans =
1 2