How to delete rows and columns that are all zeros in a 3D array?

10 views (last 30 days)
I have a 1024 by 1024 by 150 array consisting of ones and zeros. How do i delete all the rows and columns containing all zeros and no ones, excluding the ones between ones. Example:
0 0 0 0 0
0 1 1 0 1
0 1 1 0 0
0 0 0 0 0
0 1 0 0 0
would result in :
1 1 0 1
1 1 0 0
0 0 0 0 this row would not get deleted because it is between rows containing ones
1 0 0 0
Looking at the original one:
row 1 got deleted because it contained all zeros and was not sandwiched between rows of ones
row 4 would not get deleted because it is sandwiched between rows containing ones
column 1 got deleted because it contained all zeros and was not sandwiched between columns of ones
column 4 would not get deleted because it is sandwiched between rows containing ones
Can you please answer the question with regards to the 1024 by 1024 by 150 array not a simple 2D array. Thanks
  3 Comments
Mike Rovan
Mike Rovan on 28 Sep 2019
What if it were done using a structure array? That way each of the 150 slices would be stored in a cell and would be able to be a different size. So there would be 150 cells each containing a different size matrix. And Yes those columns would be considered sandwiched. Basically the goal is to start from the top, delete all rows that contain all zeros. Then when it comes across a row that contains a one it stops. Then starts from the bottom upwards and does the same, stopping when it comes across a row that contains a one. Same thing with the columns, starting from the left, deleting all columns containing all zeros and stoping when a column contains a even a single one. Then does the same starting from the right side towards the left. This way the spacing (zeros) between 2 blobs of ones stays the same and only surrounding zeros are removed

Sign in to comment.

Accepted Answer

Adam Danz
Adam Danz on 28 Sep 2019
Edited: Adam Danz on 28 Sep 2019
The first cellfun() below removes the leading and trailing columns of 0s from cell array data.
The second cellfun() below removes the leading and trailing rows of 0s from cell array data.
% demo data
data = {zeros(10,10), zeros(10,10)};
data{1}(sub2ind([10,10],[4,5,7,8],[3,5,6,7])) = 1;
data{2}(sub2ind([10,10],[3,5,7,10],[3,4,6,7])) = 1;
% Remove leading and trailing columns of 0
data = cellfun(@(x)x(:,find(any(x==1,1),1,'first'):find(any(x==1,1),1,'last')),data,'UniformOutput',false);
% [ first column with 1 ]:[ last column with 1 ]
% Remove leading and trailing rows of 0
data = cellfun(@(x)x(find(any(x==1,2),1,'first'):find(any(x==1,2),1,'last'),:),data,'UniformOutput',false);
% [ first row with 1 ]:[ last row with 1 ]
Note, if you're working with logical values rather than double 0s & 1s, you'll need to make this small change to both lines.
data = cellfun(@(x)x(:,find(any(x,1),1,'first'):find(any(x,1),1,'last')),data,'UniformOutput',false);
% here ^ here ^
  2 Comments
Mike Rovan
Mike Rovan on 28 Sep 2019
Works perfectly thanks! would you be able to explain the script a little though so that I am able to replicate it in the future. Thanks
Adam Danz
Adam Danz on 28 Sep 2019
Edited: Adam Danz on 28 Sep 2019
Glad I could help!
cellfun() applies a function to each element of a cell array, 'data'.
The function is simply to find the first and last column (or row) that contains a 1.
That is done with the function find().
data = cellfun(@(x)x(:,find(any(x==1,1),1,'first'):find(any(x==1,1),1,'last')),data,'UniformOutput',false);
% [ first column with 1 ]:[ last column with 1 ]
Sometimes it's helpful to break apart these long lines into their parts. The code below is a deconstruction of the line above but only operates on the first element of 'data'.
%Let's look at 'data'
data =
1×2 cell array
{10×10 double} {10×10 double}
data{1} % to see the matrix of 0s/1s
any(data{1}==1,1) % mark columns that contain a 1
ans =
1×10 logical array
0 0 1 0 1 1 1 0 0 0
find(any(data{1}==1,1),1,'first') % get the column number of the 1st 1
ans =
3
find(any(data{1}==1,1),1,'last') % get the column number of the LAST 1
ans =
7
% list all column numbers between the first and last
find(any(data{1}==1,1),1,'first'):find(any(data{1}==1,1),1,'last')
ans =
3 4 5 6 7
% pull out those columns from data{1}
data{1}(:,find(any(data{1}==1,1),1,'first'):find(any(data{1}==1,1),1,'last'))
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
Then we do the same for row.

Sign in to comment.

More Answers (0)

Categories

Find more on Matrices and Arrays in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!