How to select element using boolean matrix in Matlab [duplicate] - matlab

This question already has an answer here:
Linear indexing, logical indexing, and all that
(1 answer)
Closed 6 years ago.
I'm trying to select some elements by using boolean operations in MATLAB.
I have A = [1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
When using A([true true false; true true false]) I get:
1
4
7
2
Isn't it supposed to be?:
1
4
2
5
Does anyone know what's going on?

See this example for the documentation on logical indexing. It may not be explained as clearly as it should, but if you specify a logical index with fewer elements that then the indexed matrix (A) then the indexing matrix is linearized such that:
A = [1 2 3; 4 5 6; 7 8 9];
idx1 = [true true false; true true false];
A(idx1)
is equivalent to:
idx1 = [true true false; true true false];
A(idx1(:))
In other words, the index matrix (idx1) elements specify the output in column-wise order.
If you want what you though you should get, you can use:
idx2 = [true false true; true true false];
A(idx2)
or you can transform your original index array:
idx1 = [true true false; true true false];
idx2 = reshape(idx1.',2,3);
A(idx2)
or just use:
idx3 = [true true false true true].';
A(idx3)

Related

How check if pair of values exist in 2d Matlab array?

Say I have
a=[1 2 3 4; 5 6 7 8];
If I then have x=3, y=7, how can I check that (3,7) exists in array a but also ensure that if I check for the pair x=3, y=8 (3,8), then it returns false and NOT true?
EDIT: (3,7) should return true but (3,8) false because 3 and 7 are in the same column, but 3 and 8 are not. Also (7,3) should be false because for (x,y), xcorresponds to element in 1st row and y in 2nd row
EDIT2: I see isPresent = any(ismember(a.', [x y], 'rows')); for the arrray a.
But what if I have this: b=[1 5; 2 6; 3 7; 4 8]. Then how can I ensure that (3,7) is true but (7,3) is false?
The easiest way is to use ismember, but it works on rows instead of columns, so we'll need to transpose the matrix first:
x = 3;
y = 7;
a=[1 2 3 4; 5 6 7 8];
isPresent = any(ismember(a.', [x y], 'rows'));
>> isPresent
isPresent = 1

Matlab, intersection of two vectors

i want to determinate the positions when 2 vectors are intersected without using repetitive operations. For example
A = [ 2 2 3 4 5]
B = [ 2 3 3 8 5]
And the output will be
R = [1 3 5].
You can simply use find with a logical matrix:
A = [2 2 3 4 5];
B = [2 3 3 8 5];
R = find(A == B)
1 3 5
The expression A == B will create a logical matrix where an element is true (1) if the element in A is equal to the element in B and false (0) if they are not equal. Then find will identify the positions in this logical matrix where the values are true.

How to find exact number of minimum values in matrix? [duplicate]

This question already has answers here:
Get the indices of the n largest elements in a matrix
(4 answers)
Closed 8 years ago.
I want to find 3 minimum values in my matrix.
For example:
7 7 11 5 6
8 9 6 3 2
10 15 8 3 4
12 9 6 8 11
3 minimum values: 2,3,4.
Any suggestions?
If the vector is large, sorting a matrix (O(n*log n)) might take more time than doing three linear searches (O(n)). So something like this might actually be faster than sorting the array and selecting the first three values.
On my computer, this approach is faster on vectors larger than 1000-3000 elements.
num_vals = 3
vals = zeros(num_vals,1);
for k = 1:3
[min_val, idx] = min(A);
vals(ii) = min_val;
A(idx) = NaN;
end
To illustrate:
A = rand(1e6,1);
S = A;
%% Linear search:
tic
for ii = 1:10
A = S;
num_vals = 3;
vals = zeros(num_vals,1);
for ii = 1:3
[min_val, idx] = min(A);
vals(ii) = min_val;
A(idx) = NaN;
end
end
t1 = toc
A = S;
%% Sorting first:
tic
for ii = 1:10
As = sort(A(:),'ascend');
vals2 = As(1:3);
end
t2 = toc
isequal(vals, vals2)
t1 =
0.0661
t2 =
0.4781
ans =
1
Something like this:
nrItems = 3;
yourAr = [ 7 7 11 5 6 8 9 6 3 2 10 15 8 3 4 12 9 6 8 11 ];
sortAr = sort(yourAr, 'ascend');
vals = sort(1:nrItems)

Order of elements in cell array constructed by accumarray

What I'm trying to do: given a 2D matrix, get the column indices of the elements in each row that satisfy some particular condition.
For example, say my matrix is
M = [16 2 3 13; 5 11 10 8; 9 7 6 12; 4 14 15 1]
and my condition is M>6. Then my desired output would be something like
Indices = {[1 4]'; [2 3 4]'; [1 2 4]'; [2 3]';}
After reading the answers to this similar question I came up with this partial solution using find and accumarray:
[ix, iy] = find(M>6);
Indices = accumarray(ix,iy,[],#(iy){iy});
This gives very nearly the results I want -- in fact, the indices are all right, but they're not ordered the way I expected. For example, Indices{2} = [2 4 3]' instead of [2 3 4]', and I can't understand why. There are 3 occurrences of 2 in ix, at indices 3, 6, and 9. The corresponding values of iy at those indices are 2, 3, and 4, in that order. What exactly is creating the observed order? Is it just arbitrary? Is there a way to force it to be what I want, other than sorting each element of Indices afterwards?
Here's one way to solve it with arrayfun -
idx = arrayfun(#(x) find(M(x,:)>6),1:size(M,1),'Uni',0)
Display output wtih celldisp(idx) -
idx{1} =
1 4
idx{2} =
2 3 4
idx{3} =
1 2 4
idx{4} =
2 3
To continue working with accumarray, you can wrap iy with sort to get your desired output which doesn't look too pretty maybe -
Indices = accumarray(ix,iy,[],#(iy){sort(iy)})
Output -
>> celldisp(Indices)
Indices{1} =
1
4
Indices{2} =
2
3
4
Indices{3} =
1
2
4
Indices{4} =
2
3
accumarray is not guaranteed to preserve order of each chunk of its second input (see here, and also here). However, it does seem to preserve it when the first input is already sorted:
[iy, ix] = find(M.'>6); %'// transpose and reverse outputs, to make ix sorted
Indices = accumarray(ix,iy,[],#(iy){iy}); %// this line is the same as yours
produces
Indices{1} =
1
4
Indices{2} =
2
3
4
Indices{3} =
1
2
4
Indices{4} =
2
3

Get elements of vector by non-given indexes in Matlab

I have the following:
a = [1:10 1:10];
idx = [3 5 7];
b = a(idx);
b = [3 5 7];
c = a(~idx); %this syntax is not correct!
c = [1 2 4 6 8 9 10 1 2 3 4 5 6 7 8 9 10];
is there a straight forward way to get c like this? In other words I have an vector and I want to exclude the elements at the given indexes, how can I do that?
Explicit way: generate a negated logical index:
logical_idx = true(1,numel(a));
logical_idx(idx) = false;
c = a(logical_idx);
More compact code using setdiff or ismember:
c = a(setdiff(1:numel(a), idx));
or
c = a(~ismember(1:numel(a), idx));
Directly remove elements indexed by idx:
c = a;
c(idx) = [];