Related
I have a binary vector, e.g:
x = [1 1 1 0 0 1 0 1 0 0 0 1]
I want to keep the first 4 elements that are '1' (substituting the rest with '0's). In my example the resulting vector should be:
z = [ 1 1 1 0 0 1 0 0 0 0 0 0]
Any help would be much appreciated.
First construct a vector of zeroes, then use find:
z = false(size(x));
z(find(x, 4)) = true;
No need for find for a binary vector. Use cumsum instead!
>> z = x;
>> z(cumsum( z, 2 ) > 4) = 0;
This solution (unlike find-based answers) can process a stack of such binary vectors at once (all you need is to verify that cumsum works on the proper dimension).
Try following:
z=x;
A=find(z);
z(A(5:end))=0;
Idea here is to make all, but first n, 1's to 0's
I have one matrix like below-
A=[1 1 1 1 1;
0 1 1 1 2;
0 0 1 1 3]
But I want to place all the 0 at the end of the row, so A should be like-
A=[1 1 1 1 1;
1 1 1 2 0;
1 1 3 0 0]
How can I do this? Matlab experts please help me.
There you go. Whole matrix, no loops, works even for non-contiguous zeros:
A = [1 1 1 1 1; 0 1 1 1 2; 0 0 1 1 3];
At = A.'; %// It's easier to work with the transpose
[~, rows] = sort(At~=0,'descend'); %// This is the important part.
%// It sends the zeros to the end of each column
cols = repmat(1:size(At,2),size(At,1),1);
ind = sub2ind(size(At),rows(:),cols(:));
sol = repmat(NaN,size(At,1),size(At,2));
sol(:) = At(ind);
sol = sol.'; %'// undo transpose
As usual, for Matlab versions that do not support the ~ symbol on function return, change ~ by a dummy variable, for example:
[nada, rows] = sort(At~=0,'descend'); %// This is the important part.
A more generic example:
A = [1 3 0 1 1;
0 1 1 1 2;
0 0 1 1 3]
% Sort columns directly
[~,srtcol] = sort(A == 0,2);
% Sorted positions
sz = size(A);
pos = bsxfun(#plus, (srtcol-1)*sz(1), (1:sz(1))'); % or use sub2ind
The result
B = A(pos)
B =
1 3 1 1 0
1 1 1 2 0
1 1 3 0 0
there are many ways to do this. one fast way can be easily like this:
a = [1 2 3 4 0 5 7 0];
idx=(find(a==0));
idx =
5 8
b=a; % save a new copy of the vector
b(idx)=[]; % remove zero elements
b =
1 2 3 4 5 7
c=[b zeros(size(idx))]
c =
1 2 3 4 5 7 0 0
You may modify this code as well.
If your zeros are always together, you could use the circshift command. This shifts values in an array by a specified number of places, and wraps values that run off the edge over to the other side. It looks like you would need to do this separately for each row in A, so in your example above you could try:
A(2,:) = circshift(A(2,:), [1 -1]); % shift the second row one to the left with wrapping
A(3,:) = circshift(A(3,:), [1 -2]); % shift the third row two to the left with wrapping
In general, if your zeros are always at the front of the row in A, you could try something like:
for ii = 1:size(A,1) % iterate over rows in A
numShift = numel(find(A(ii,:) == 0)); % assuming zeros at the front of the row, this is how many times we have to shift the row.
A(ii,:) = circshift(A(ii,:), [1 -numShift]); % shift it
end
Try this (just a fast hack):
for row_k = 1:size(A, 1)
[A_sorted, A_sortmap] = sort(A(row_k, :) == 0, 'ascend');
% update row in A:
A(row_k, :) = A(row_k, A_sortmap);
end
Now optimized for versions of MATLAB not supporting ~ as garbage lhs-identifier.
#LuisMendo's answer is inspiring in its elegance, but I couldn't get it to work (perhaps a matlab version thing). The following (based on his answer) worked for me:
Aaux = fliplr(reshape([1:numel(A)],size(A)));
Aaux(find(A==0))=0;
[Asort iso]=sort(Aaux.',1,'descend');
iso = iso + repmat([0:size(A,1)-1]*size(A,2),size(A,2),1);
A=A.';
A(iso).'
I've also asked this question and got a super elegant answer (non of above answers is same) here:
Optimize deleting matrix leading zeros in MATLAB
For each column of a matrix A consisting of '0' and '1', I would like to find the column indices of the first occurrence of '1' if exists. For example, if A is defined as:
A=[0 0 0 0;
0 0 0 1;
0 0 0 0;
0 0 0 1;
1 0 0 0;
0 1 0 1;
1 1 0 0]
then the result would be:
b=[5 6 2]
I'm searching for a solution without any 'for' or 'while' loops.
One solution I came up with:
[b,~]=find(cumsum(cumsum(A))==1)
Is there a more elegant way to do this?
This is shorter than anything posted and it's a one liner.
Code:
[~,idx] = max(A(:,sum(A)>0));
Output:
idx =
5 6 2
EDIT: Just realized you can do:
[~,idx] = max(A(:,any(A)))
#Nacer - nice answer. By default [a,m,c] = unique(J) returns the vector m to index the last occurrence of each unique value in J. Use [~,m] = unique(J, 'first'); instead.
[I,J] = find(A==1);
[~,m] = unique(J, 'first');
I(m)
ans =
5
6
2
Say I have the following matrix:
1 0 1 1 0 0
0 0 1 0 1 0
1 1 1 0 0 1
0 1 1 0 0 1
1 1 1 1 1 0
I want to convert it to a different format, where I replace each 1 in each row by its column index, so it would become the following:
1 0 3 4 0 0
0 0 3 0 5 0
1 2 3 0 0 6
0 2 3 0 0 6
1 2 3 4 5 0
I can do it the 'dumb' way:
[H, W] = size(a);
for i = 1:H
for j = 1:W
if(a(i, j) == 1)
a(i, j) = j;
end
end
end
But there surely must be a way to do it with one line (perhaps using the 'find' function), anyone know how?
This isn't super general but does what you want. find returns indices into the one-dimensional version of the data, so we need to do a little arithmetic to get the two-d versions:
a(a == 1) = floor((find(a == 1) - 1) / size(a, 1)) + 1
If you wanted to do the row indices instead, you could use
a(a == 1) = mod(find(a == 1) - 1, size(a, 1)) + 1
If you were doing this with a big matrix, you might want to assign find(a == 1) to a temporary variable first:
inds = find(a == 1)
a(inds) = floor((inds - 1) / size(a, 1)) + 1
(Note that indexing into a with either a list of indices or a matrix of booleans works the same.)
You could also just use find(a) if you know the original matrix is only 0s and 1s.
Note that this is just doing manually basically what #tmpearce's answer does.
you have a matrix a
[r,c]=ind2sub(size(a),find(a));
a(find(a))=c;
Edit: this is doable in one line, since that's important to you:
[r,a(find(a))]=ind2sub(size(a),find(a));
You can use meshgrid to do this:
[H, W] = size(a);
a = a.*meshgrid(1:H,1:W);
It's been a long time since I have use matlab, so I wont be able to give you the code out of my head. But here is the way I would do it:
Create a vector 1:colums, repeat it once for each row using repmat and then multiply this elementwise with the original matrix.
Also since loops are slow in matlab whereas matrix operations are fast, such a one liner will probably be much faster than the code you have right now.
hi i have the following situation
h = [0,1,1,1;
0,0,0,0;
1,1,1,1];
i'll check incoming values which can range between 0 and rowsize of h, i.e. in this case 2,. so my options are 0,1,2.
now i want to create a single dimensional array (let's name it j) as follows
whenever the incoming value is 0
j = [0,1,1,1]
next time if the incoming value is 1
then j = [0,1,1,1,0,0,0,0]
and so on... how is it possible to achieve this in matlab? thanks!
Matlab, as you know, indexes from 1 so you will need to add 1 to the index 0,1,2 to get the row identifier for h. So if the input is 'index'
j = h(index+1,:)
Then, for the next index
j = [j h(index+1,:)]
and so on.
Try this (with x as your vector of incoming values):
j = reshape(h(x+1,:).',1,[]);
The above uses x+1 as an index to select copies of the rows, then transposes and reshapes the result into a single row vector. Here's a test:
>> h = [0 1 1 1; 0 0 0 0; 1 1 1 1];
>> x = [0 0 0];
>> j = reshape(h(x+1,:).',1,[])
j =
0 1 1 1 0 1 1 1 0 1 1 1
If the incoming value is x, you could do something like:
g = h.'
j = g(1:(x+1)*size(h,2))