find in multidimensional array - MATLAB - matlab

I have a 3 by 3 by 2 by 3 array X containing 1s or 0s. Picture this as a row of three 3 by 3 matrices along a row and another such 'layer' behind them (from the '2').
I want to find the positions in X of the 0s in the first layer and second layer separately. I'm not really sure how to do this with find, but heuristically something like:
A = find(X == 0 & 3rd index of X is 1)
B = find(X == 0 & 3rd index of X is 2)
EDIT
I just realised my attempt to simplify my actual question made it misleading. The array X actually has -1's, 1's and -2's and I want to find the -2's. They're not meant to be logical operators. Also I would prefer any operation proposed to be as fast as possible as this will be part of a recursive backtracking algorithm.

solution using logical indexing
I recommend to use logical indexing instead of find.
This gives you all indices where X is 1
value_you_want=-2
C=X==value_you_want;
Now you want only parts of these indices in A and B, first initialize A and B with false of the same size as C:
A=false(size(C));
B=A;
And finally copy the slice you want to each of these matrices:
A(:,:,1,:)=C(:,:,1,:);
B(:,:,2,:)=C(:,:,2,:);
If you really want your numeric indices, use find(A) and find(B)
Alternative solution using linear indices and find
%get all indices
C=find(X==value_you_want)
%convert linear indices to subscript indices, only use third dimension
[~,~,S,~]=ind2sub(size(X),find(X==0));
%Use S to split C
A=C(S==1);
B=C(S==2);

Generally use find(condition) to return linear indices in the array satisfying condition.
A = find(A(:,:,1,:)<1)
B = find(A(:,:,2,:)<1)

Related

How to use `find` to find the indices of each page of a 3D matrix?

I have a 3D matrix that each page/slice is independent of other slices. Thus, I would like to use the find command to filter my data in each page. However, when applied, find will return the indices in a row vector that describe my data as a whole, where actually it is not. For example:
a=rand(1,10,5);
ind=find(a<0.3);
This would return ind something like:
ind=
1 2 5 9 10 11 20 24 25 ...
I expected something like:
ind(:,:,1)=
1 2 3
ind(:,:,2)=
1 5 6 10 %based on each slice, independent to other slices
I intended to do so (independently), so that I could apply the found indices to each slice of other matrix.
Can this be done without using loop? Thanks in advance!
Use ind2sub() to convert your indices to subscripts. Something like this should work for a 3d array:
[i,j,k] = ind2sub(size(a), ind)
That said, the outputs (i, j, k), will all be the same size, that is the same size as ind. In other words, it gives one set of subscripts (i,j,k) (coordinates) for each value of a<0.3.
It's not completely clear what output you want/expect from your question, but if you want separate subscripts for each page in a, you'll have to filter further (e.g. j(i==1),k(i==1) for the first page in i).

Matlab: Create a zero matrix with 1 in a particular place

For example, I can create a zeros(100). But I want the entry of row 58 and column 59 to be 1. But I need temporary variable and multiple lines to do this.
a. Let this matrix be M. How can I do this in one line? M = ....?
P.S.
b. Better still, sometimes I want two or more entries of the zero matrix be 1.
Again, how can I do this?
If I can do a. in one-line, of course I can add them up. But is there any special function to do fill zero matrix entries with 1?
First, remember that a one line expression isn't always the most effective. It could also be harder to read/understand.
One way to do this is by using a sparse matrix
The following example creates a 10x10 zero-matrix with ones at [5,2] (row 5, col 2) and [7 5]
full(sparse([5 7],[2 5],1,10,10))
Use full to convert it from a sparse matrix to a "full" one
Another (faster but maybe not as intuitive) alternative is to use accumarray
accumarray([5 2;7 5],1,[10,10])
Remember that the index values above is used directly in the expression to get on one line, the better option would be to create them separately
points = [5 2; 7 5]
or perhaps,
rowIdx = [5 7];
colIdx = [2 5];

Assigning the different row to another matrix after comparing two matrices

i have two matrices
r=10,000x2
q=10,000x2
i have to find out those rows of q which are one value or both values(as it is a two column matrix) different then r and allocate them in another matrix, right now i am trying this.i cannot use isequal because i want to know those rows
which are not equal this code gives me the individual elements not the complete rows different
can anyone help please
if r(:,:)~=q(:,:)
IN= find(registeredPts(:,:)~=q(:,:))
end
You can probably do this using ismember. Is this what you want? Here you get the values from q in rows that are different from r.
q=[1,2;3,4;5,6]
r=[1,2;3,5;5,6]
x = q(sum(ismember(q,r),2) < 2,:)
x =
3 4
What this do:
ismember creates an array with 1's in the positions where q == r, and 0 in the remaining positions. sum(.., 2) takes the column sum of each of these rows. If the sum is less than 2, that row is included in the new array.
Update
If the values might differ some due to floating point arithmetic, check out ismemberf from the file exchange. I haven't tested it myself, but it looks good.

matlab: addressing of one index without sub2ind

This is very closely related to this other question, but that question wanted to avoid sub2ind because of performance concerns. I am more concerned about the "unelegance" of using sub2ind.
Let's suppose I want to create another MxN matrix which is all zeros except for one entry in each column that I want to assign from the corresponding entry in a vector, and choice of row in each column is based on another vector. For example:
z = zeros(10,4);
rchoice = [3 1 8 7];
newvals = [123 456 789 10];
% ??? I would like to set z(3,1)=123, z(1,2)=456, z(8,3)=789, z(7,4)=10
I can use sub2ind to accomplish this (which I used in an answer to a closely related question):
z(sub2ind(size(z),rchoice,1:4)) = newvals
but is there another alternative? Seems like logical addressing could be used in some way but I'm stumped, because in order to set the elements of a logical matrix to 1, you're dealing with the same element positions as in the matrix you actually want to address.
There's a much simpler way of doing it.
nCols=size(z,2);
z(rchoice,1:nCols)=diag(newvals);
You can just add the number of rows in previous columns to rchoice to get the linear index directly.
nRows = size(z,1); %# in case you don't know this already
nCols2write = length(newvals);
z(rchoice+[0:nRows:(nRows*(nCols2write-1)]) = newvals;

Compact MATLAB matrix indexing notation

I've got an n-by-k sized matrix, containing k numbers per row. I want to use these k numbers as indexes into a k-dimensional matrix. Is there any compact way of doing so in MATLAB or must I use a for loop?
This is what I want to do (in MATLAB pseudo code), but in a more MATLAB-ish way:
for row=1:1:n
finalTable(row) = kDimensionalMatrix(indexmatrix(row, 1),...
indexmatrix(row, 2),...,indexmatrix(row, k))
end
If you want to avoid having to use a for loop, this is probably the cleanest way to do it:
indexCell = num2cell(indexmatrix, 1);
linearIndexMatrix = sub2ind(size(kDimensionalMatrix), indexCell{:});
finalTable = kDimensionalMatrix(linearIndexMatrix);
The first line puts each column of indexmatrix into separate cells of a cell array using num2cell. This allows us to pass all k columns as a comma-separated list into sub2ind, a function that converts subscripted indices (row, column, etc.) into linear indices (each matrix element is numbered from 1 to N, N being the total number of elements in the matrix). The last line uses these linear indices to replace your for loop. A good discussion about matrix indexing (subscript, linear, and logical) can be found here.
Some more food for thought...
The tendency to shy away from for loops in favor of vectorized solutions is something many MATLAB users (myself included) have become accustomed to. However, newer versions of MATLAB handle looping much more efficiently. As discussed in this answer to another SO question, using for loops can sometimes result in faster-running code than you would get with a vectorized solution.
I'm certainly NOT saying you shouldn't try to vectorize your code anymore, only that every problem is unique. Vectorizing will often be more efficient, but not always. For your problem, the execution speed of for loops versus vectorized code will probably depend on how big the values n and k are.
To treat the elements of the vector indexmatrix(row, :) as separate subscripts, you need the elements as a cell array. So, you could do something like this
subsCell = num2cell( indexmatrix( row, : ) );
finalTable( row ) = kDimensionalMatrix( subsCell{:} );
To expand subsCell as a comma-separated-list, unfortunately you do need the two separate lines. However, this code is independent of k.
Convert your sub-indices into linear indices in a hacky way
ksz = size(kDimensionalMatrix);
cksz = cumprod([ 1 ksz(1:end-1)] );
lidx = ( indexmatrix - 1 ) * cksz' + 1; #'
% lindx is now (n)x1 linear indices into kDimensionalMatrix, one index per row of indexmatrix
% access all n values:
selectedValues = kDimensionalMatrix( lindx );
Cheers!