Assign sequential number to integer element in array - arrays

Good morning/afternoon~
I have an array like this,
A= [12 0 0 0 0 3 0 0 0 66 0 0 0 0 20 0 0 2 0 31 0 0 42 0 32 0 38]
the output should be:
B= [ 1 0 0 0 0 2 0 0 0 3 0 0 0 0 4 0 0 5 0 6 0 0 7 0 8 0 9]
What should I do to replace the non-zero elements in A with sequential number?

This will do it:
A(A ~= 0) = 1:nnz(A)

A(ismember(A,A(A(:) ~=0))) = 1:numel(A(A(:) ~=0))

With the image processing toolbox (will give the same label to adjacent non-zero values, though):
B = bwlabel(A)

B = cumsum(A ~= 0) .* (A ~= 0);

Related

Why does summing the rows in this matrix give me 0?

I created an array A by first using the command A = [1:10]'.
Then I created a 10x10 matrix, only containing 0's. I then overwrote this matrix with my A, resulting in this new matrix:
A =
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 0 0
8 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0
10 0 0 0 0 0 0 0 0 0
Now the problem is, when I run the command sum((A(1,1)):(A(1,end))), I keep getting 0 when I should be getting 1, as it is the sum of the first row. I tried running the same command on other matrices and they give me the correct answer, so why isn't it working here?
The term
(A(1,1)):(A(1,end))
creates and empty array, as A(1,1) = 1 and A(1,end) = 0 which makes it impossible for colon : to create a vector, so the sum over it is zero. But its not what you want anyway, I guess.
What you supposedly want is
sum(A(1,:))
or in respect to whole matrix, by specifying the dimension of the sum, e.g.
sum(A,2)
ans =
1
2
3
4
5
6
7
8
9
10
Edit
If you want to start from a different column index you can do the following:
sum( A(rowIndex,firstColumnIndex:lastColumnIndex) )
while end can be used as macro variable for the last index of the corresponding column or row.

Create a matrix blockwise attaching blocks like a stairway MATLAB

I want to build an Array containing of different blocks in the following way.
Given the block I want to repeat the block n-times so that it looks like this:
A =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and I want the Array look like this, n times repeating the scheme:
newArray =
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
1 0 0 -1 0 0 0 0 0 1 0 0
0 1 0 0 -1 0 0 0 0 0 1 0
0 0 1 0 0 -1 0 0 0 0 0 1
and so on...
With the free space being zeros, since the final array should be a sparse array either way.
How can I repeat and attach the block without using loops?
I'm assuming that the leftward offset of each block with respect to a pure block-diagonal matrix is the number of rows of A, as in your example.
You can build a matrix t that 2D-convolved with A gives the result, as follows:
A = [1 2 3 4; 5 6 7 8]; % data matrix
n = 3; % number of repetitions
[r, c] = size(A);
d = c-r;
t = zeros(r*(n-1)+1, d*(n-1)+1);
t(1:(r*(n-1)+1)*d+r:end) = 1;
result = conv2(t,A);
This gives
A =
1 2 3 4
5 6 7 8
result =
1 2 3 4 0 0 0 0
5 6 7 8 0 0 0 0
0 0 1 2 3 4 0 0
0 0 5 6 7 8 0 0
0 0 0 0 1 2 3 4
0 0 0 0 5 6 7 8
Here is a solution using kron:
n = 5; % number of repetitions
v = 3; % overlapping
s = size(A);
B = A(:,1:s(2)-v)
C = zeros(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v)=0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);
When the matrix size is large you can use sparse matrix:
n = 5;
v = 3;
s = size(A);
B = sparse(A(:,1:s(2)-v));
C = sparse(s(1),s(2)-v);
C(:,end-v+1:end) = A(:,end-v+1:end);
result = kron(eye(n) , B);
result(end,end+v) = 0;
result(:,v+1:end) = result(:,v+1:end) + kron(eye(n) , C);

Find regions of contiguous zeros in a binary array

I have
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
I want to find all the regions that have more than 5 zeros in a row. I want to find the index where it starts and where it stops.
In this case I want this: c=[12 18]. I can do it using for loops but I wonder if there is any better way, at least to find if there are some regions where this 'mask' ( mask=[0 0 0 0 0] ) appears.
A convolution based approach:
n = 5;
x = [0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0];
end_idx = find(diff(conv(~x, ones(1,n))==n)==-1)
start_idx = find(diff(conv(~x, ones(1,n))==n)==1) - n + 2
returning
end_idx =
6 14 25
start_idx =
1 9 20
Note that this part is common to both lines: diff(conv(~x, ones(1,n))==n) so it would be more efficient to pull it out:
kernel = ones(1,n);
convolved = diff(conv(~x, kernel)==n);
end_idx = find(convolved==-1)
start_idx = find(convolved==1) - n + 2
You can use regexp this way:
convert the array into a string
remove the blanks
use regexp to find the sequence of 0
A possible implementation could be:
x=[ 1 1 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1]
% Convert the array to string and remove the blanks
str=strrep(num2str(x),' ','')
% Find the occurrences
[start_idx,end_idx]=regexp(str,'0{6,}')
This gives:
start_idx = 12
end_idx = 17
where x(start_idx) is the first element of the sequence and x(end_idx) is the last one
Applied to a more long sequence, start_idx and end_idx results being arrays:
x=[0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0]
start_idx =
1 9 20
end_idx =
6 14 25

Convert integer to logical array in MATLAB

I want to convert an integer i to a logical vector with an i-th non-zero element. That can de done with 1:10 == 2, which returns
0 1 0 0 0 0 0 0 0 0
Now, I want to vectorize this process for each row. Writing repmat(1:10, 2, 1) == [2 5]' I expect to get
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
But instead, this error occurs:
Error using ==
Matrix dimensions must agree.
Can I vectorize this process, or is a for loop the only option?
You can use bsxfun:
>> bsxfun(#eq, 1:10, [2 5].')
ans =
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Note the transpose .' on the second vector; it's important.
Another way is to use eye and create a logical matrix that is n x n long, then use the indices to index into the rows of this matrix:
n = 10;
ind = [2 5];
E = eye(n,n) == 1;
out = E(ind, :);
We get:
>> out
out =
0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Just another possibility using indexing:
n = 10;
ind = [2 5];
x=zeros(numel(ind),n);
x(sub2ind([numel(ind),n],1:numel(ind),ind))=1;

matlab matrix from array

I have large array. Now I need a matrix with 8 elements in every row. My array looks like this:
A= Columns 1 through 18
0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 1 0 0
Columns 19 through 36
0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0
and so on. How I can get [nx8] matrix? For example:
B=[0 0 0 0 0 0 0 0
0 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0]
I've tried reshape, but it didn't work correctly. I get one 1 where shouldn't be.
B=reshape(A,[],8)
You almost have it. The problem is that Matlab fills the matrix column-wise, whereas you seem to want it filled row-rise. So create an 8-row matrix and then transpose:
reshape(A,8,[]).'
What about vec2mat
vec2mat
vec2mat(A,8)

Resources