SMH
SMH

Reputation: 1316

Create a vector that holds the index of all the columns which has non-zero values based on a condition

I have a matrix filled with zeros and ones and I need to count the number of ones in each row. Then I need to know which row's count exceeds or equal a specific limit (any number, for example 3). After that foreach row in these rows I need to create a vector that holds the index of all the columns which has non-zero values in that row and in all the rows above it and below it till it reach a row with zero count.

Example: data contains the data below:

0 0 0 0 0 0 0
0 0 0 1 1 0 0
0 1 0 0 1 0 1
0 0 0 0 0 0 0
0 1 0 0 0 0 0 
0 1 1 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0

The output should be if the limit is 3:

Row 3: col 4 5 2 5 7 
Row 6: col 2 2 3 4 3 

I already read the data and I counted the ones in the code below:

load('data');
mat(isnan(mat)) = 0;
[rows,cols,vals]  = find(mat~= 0);
unqRows=unique(rows);
countElinRows=histc(rows,unqRows);

Edit for clarification as requested by commentators:

If the third row of the given sample input array becomes [0 1 0 0 0 0 1], then we must only have this output -

Row 6: col 2 2 3 4 3

Upvotes: 1

Views: 94

Answers (2)

Divakar
Divakar

Reputation: 221584

Assuming A as the input array, see if this works for you -

[sc1,sr1] = find(A') %//'# row and col indices for sorted rows
s_a1 = sum(A,2) %// sum input array along cols
bounds = find(s_a1==0) %// find bounds/gropus delimited by all zero rows
bounds = unique([1 ; bounds ; size(A,1)]) %// account for non all zero 
                                         %// starting and ending rows

cumsum1 = cumsum(s_a1==0) + double(sum(A(1,:))~=0) %// label groups

valid_groups = accumarray(cumsum1, s_a1, [], @max)>=3 %// valid groups

out = arrayfun(@(k1) sc1(sr1>=bounds(k1) & sr1<=bounds(k1+1)),...
    1:numel(bounds)-1,'un',0) %// find all indices within each group
out = out(valid_groups) %// select only the valid groups for the final output

Visualized output with celldisp(out).

Upvotes: 1

David
David

Reputation: 8459

Apologies for strange code, but it's the best I could come up with

[I1,~]=find(sum(mat,2)>=3)
[I2,~]=find(sum(mat,2)==0)
[~,CM]=find(diff(mod(sum(bsxfun(@le,I1,I2.')),2))~=0)
[I,J]=arrayfun(@(t)find(mat(I2(CM(t)):I2(CM(t)+1),:)>0),1:length(CM),'UniformOutput',false)
[~,w]=cellfun(@sort,I,'UniformOutput',false);
J=arrayfun(@(t) J{t}(w{t}).',1:length(J),'UniformOutput',false)
celldisp(J)

This code does feel pretty overcomplicated.

I have tested it on a few cases and it seems to be fine, but it's hard to know for certain.

Upvotes: 1

Related Questions