Remove surrounding zeroes of a 2d array

40

2

This is a 2-dimensional version of this question.

Given a non-empty 2-dimensional array/matrix containing only non-negative integers:

$$ \begin{bmatrix} {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & {\color{Red}0} & 0 & 1 & 0 \\ {\color{Red}0} & {\color{Red}0} & 0 & 0 & 1 \\ {\color{Red}0} & {\color{Red}0} & 1 & 1 & 1 \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \end{bmatrix} $$

Output the array with surrounding zeroes removed, i.e. the largest contiguous subarray without surrounding zeroes:

$$ \begin{bmatrix} 0 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 1 & 1 \end{bmatrix} $$

Examples:

$$ \begin{bmatrix} {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & {\color{Red}0} & 0 & 1 & 0 \\ {\color{Red}0} & {\color{Red}0} & 0 & 0 & 1 \\ {\color{Red}0} & {\color{Red}0} & 1 & 1 & 1 \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \end{bmatrix} \mapsto \begin{bmatrix} 0 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 1 & 1 \end{bmatrix} $$

Input:
[[0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0]]

Output:
[[0, 1, 0], [0, 0, 1], [1, 1, 1]]

$$ \begin{bmatrix} {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & 0 & 0 & 3 \\ {\color{Red}0} & 0 & 0 & 0 \\ {\color{Red}0} & 5 & 0 & 0 \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \end{bmatrix} \mapsto \begin{bmatrix} 0 & 0 & 3 \\ 0 & 0 & 0 \\ 5 & 0 & 0 \end{bmatrix} $$

Input:
[[0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0], [0, 5, 0, 0], [0, 0, 0, 0]]

Output:
[[0, 0, 3], [0, 0, 0], [5, 0, 0]]

$$ \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} \mapsto \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix} $$

Input:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

$$ \begin{bmatrix} {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \end{bmatrix} \mapsto \begin{bmatrix} \end{bmatrix} $$

Input:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Output:
[]

$$ \begin{bmatrix} {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \\ 1 & 1 & 1 & 1 \\ {\color{Red}0} & {\color{Red}0} & {\color{Red}0} & {\color{Red}0} \end{bmatrix} \mapsto \begin{bmatrix} 1 & 1 & 1 & 1 \end{bmatrix} $$

Input:
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]]

Output:
[[1, 1, 1, 1]]

$$ \begin{bmatrix} {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \\ {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \end{bmatrix} \mapsto \begin{bmatrix} 1 \\ 1 \\ 1 \end{bmatrix} $$

Input:
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]

Output:
[[1], [1], [1]]

$$ \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 1 \\ 1 & 1 & 1 & 1 \end{bmatrix} \mapsto \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 1 \\ 1 & 1 & 1 & 1 \end{bmatrix} $$

Input:
[[1, 1, 1, 1], [1, 2, 3, 1], [1, 1, 1, 1]]

Output:
[[1, 1, 1, 1], [1, 2, 3, 1], [1, 1, 1, 1]]

alephalpha

Posted 2018-07-27T13:41:24.673

Reputation: 23 988

This is very difficult in JavaScript. I'm looking forward to a concise answer in that language. – MattH – 2018-07-27T15:40:29.633

3@MattH Nothing is difficult in a non-esoteric language. :) Just difficult to make it short. – user202729 – 2018-07-27T16:20:05.920

1Can we give a falsey output instead of an empty matrix, for the last test case? – sundar - Reinstate Monica – 2018-07-27T18:21:34.160

1Also, if output can be a non-square matrix, please add a test case for that. – sundar - Reinstate Monica – 2018-07-27T18:44:52.277

1A test case that broke my earlier submission: [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]] (the result having a width/height of 1) – Conor O'Brien – 2018-07-27T20:24:22.077

@sundar What does that falsey value look like? If it is just false, I think it is OK. – alephalpha – 2018-07-28T04:04:45.550

1Hey, is it possible to add the test case $$\begin{bmatrix}1&1&1&1\1&2&3&1\1&1&1&1\end{bmatrix}$$ – Beta Decay – 2018-07-28T10:35:23.440

1I would suggest adding a test case like this as well:

$$ \begin{bmatrix} {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \ {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \ {\color{Red}0} & 1 & {\color{Red}0} & {\color{Red}0} \end{bmatrix} $$ – Night2 – 2018-07-28T12:00:16.827

Answers

12

MATL, 3 bytes

JYa

Try it online! Or verify all test cases.

Explanation

J      % Push 1j
Ya     % With complex 2nd input, this unpads the matrix in the
       % 1st input (implicit). The unpad value is 0 by default
       % Display (implicit)

Luis Mendo

Posted 2018-07-27T13:41:24.673

Reputation: 87 464

7"JYa JYa JYa JYa" – Brain Guider – 2018-07-27T15:09:31.550

5I like how half the code is just (implicit). – JungHwan Min – 2018-07-27T20:11:57.340

39

Wolfram Language (Mathematica), 42 bytes

#&@@CellularAutomaton[{,{},0{,}},{#,0},0]&

Try it online!

Cellular automata are indeed the answer to life, the universe, and everything.1

How?

CellularAutomaton accepts an input array and an optional background value. Thus, {#,0} specifies that a cellular automaton rule should be applied to the input, assuming a background of 0s.

A neat thing here is that CellularAutomaton crops the output so that no border of background cells is present (because otherwise the output lies on an infinite plane).

The code applies the rule {Null, {}, {0, 0}} -- applying the head Null to the 0-radius neighbor of each cell (i.e. only the center: the cell itself) -- exactly 0 times. The result of this is the original input, but with background removed (i.e. cropping out surrounding 0s).


1. See the bytecount of my answer? ;)

JungHwan Min

Posted 2018-07-27T13:41:24.673

Reputation: 13 290

6Nice builtin abuse... well Mathematica has a built-in, just not exposed directly. – user202729 – 2018-07-27T14:48:13.937

3

No XKCD 505 reference?

– Esolanging Fruit – 2018-07-30T00:05:47.627

+1 for Cellular Automata & the Ultimate Answer. – HighlyRadioactive – 2019-09-28T04:55:32.393

14

JavaScript (ES6), 98 bytes

(a,z)=>(g=A=>A.slice(A.map(m=M=(r,i)=>M=(z?a:r).some(n=>z?n[i]:n)?1/m?i:m=i:M)|m,M+1))(a).map(z=g)

Try it online!

How?

To overcome the lack of a zip built-in, we define a function g() that is able to operate on either the rows or the columns of the input matrix a[ ], depending on the value of the global flag z.

g() looks for the minimum index m and maximum index M of either non-empty rows (if z is undefined) or non-empty columns (if z is defined) and returns the corresponding slice of either the matrix itself or a given row of the matrix.

To summarize:

  • we first remove rows by invoking g() on the matrix with z undefined
  • we then remove columns by invoking g() on each row with z defined, which leads to this rather unusual .map(z=g)

Commented

(a, z) => (               // a[] = input matrix; z is initially undefined
  g = A =>                // g() = function taking A = matrix or row
    A.slice(              //   eventually return A.slice(m, M + 1)
      A.map(m = M =       //     initialize m and M to non-numeric values
        (r, i) =>         //     for each row or cell r at position i in A:
        M = (z ? a : r)   //       iterate on either the matrix or the row
        .some(n =>        //       and test whether there's at least one
          z ? n[i] : n    //       non-zero cell in the corresponding column or row
        ) ?               //       if so:
          1 / m ? i       //         update the maximum index M (last matching index)
                : m = i   //         and minimum index m (first matching index)
        :                 //       otherwise:
          M               //         let M (and m) unchanged
      ) | m,              //     end of map(); use m as the first parameter of slice()
      M + 1               //     use M+1 as the second parameter of slice()
    )                     //   end of slice()
  )(a)                    // invoke g() on the matrix with z undefined
  .map(z = g)             // invoke g() on each row of the matrix with z defined

Arnauld

Posted 2018-07-27T13:41:24.673

Reputation: 111 334

2That is impressive. – Jack Hales – 2018-07-28T02:40:01.967

3@Jek, Arnauld lives in a whole different dimension. But if you're extremely lucky, you can occasionally find a trick that he missed and post a shorter solution. In the process, you'll develop a very deep understanding of JavaScript. – Rick Hitchcock – 2018-07-28T11:35:53.657

4@RickHitchcock I'm not that good at code pattern recognition and I'm regularly missing a lot of things, even if I've seen them before. In this particular example, I was focused on the reusability of g() and missed quite an obvious optimization on the way to update m and M (-9 bytes). I fully agree that code-golfing is a great (and fun) way to learn a lot about the subtleties of a language. – Arnauld – 2018-07-28T11:51:27.833

7

Haskell, 62 61 bytes

f.f.f.f
f=reverse.foldr(zipWith(:))e.snd.span(all(<1))
e=[]:e

Try it online!

foldr(zipWith(:))e with e=[]:e is a slightly shorter transpose, and snd.span(all(<1)) drops leading lists of zeros from a list of list. As transpose followed by reverse on a 2D list equals an rotation by 90°, the code f.f.f.f is just four times drop leading lists of zeros and rotate.

Laikoni

Posted 2018-07-27T13:41:24.673

Reputation: 23 676

6

Pyth, 13 bytes

V2=.sCQ]m0Q;Q

Try it online!

user202729

Posted 2018-07-27T13:41:24.673

Reputation: 14 620

I think =_CQ would work in place of =Q_CQ. – Mr. Xcoder – 2018-07-27T18:29:57.120

5

R, 96 100 97 bytes

function(m)m[~m,~t(m),drop=F]
"~"=function(x,z=seq(r<-rowSums(x)))z>=min(y<-which(r>0))&z<=max(y)

Try it online!

The ~ helper takes a non-negative vector and returns a vector with FALSE for the "exterior" 0s of the vector and TRUE for positives and any "interior" 0s. This function is applied to the row and column sums of the input matrix.

~ and ! use R's parser treatment of operators.

Corrected as per @DigEmAll's comment, but with some bytes golfed back from @J.Doe

ngm

Posted 2018-07-27T13:41:24.673

Reputation: 3 974

1

I think you should add drop=F as I did, otherwise these 2 tests will return a vector instead of row and column : Try it online!

– digEmAll – 2018-07-28T13:24:57.843

97 bytes with drop=F. Still under a ton! – J.Doe – 2018-10-03T14:36:03.830

5

Jelly, 10 bytes

œr€0z0Uµ4¡

Try it online!

Erik the Outgolfer

Posted 2018-07-27T13:41:24.673

Reputation: 38 134

5

Brachylog, 24 22 20 19 bytes

{s.h+>0∧.t+>0∧}\↰₁\

Try it online!

Outputs the result matrix as an array of arrays, or false for empty output.

(Thanks to @Fatalize for suggesting inline predicate and saving 1 byte.)

Explanation

Predicate 0 (Main):

{...}     Define and call predicate 1 to remove all-zero rows
  \       Transpose the result
   ↰₁     Call pred 1 again, now to remove all-zero columns
     \    Transpose the result to have correct output orientation

Predicate 1:

?s.h+>0∧.t+>0∧
  .           output is
 s              a subsequence of the rows of
?              the input (implicit)
   h          also, output's head element (first row)
    +>0        has a sum > 0 (i.e. has at least one non-zero value)
       ∧.t+>0  and similarly the output's tail element (last row)
∧              (don't implicitly unify that 0 with the output)

sundar - Reinstate Monica

Posted 2018-07-27T13:41:24.673

Reputation: 5 296

Writing the first predicate inline is 1 byte shorter: {s.h+>0∧.t+>0∧}\↰₁\. (this is true for pretty much any Brachylog answer, predicates on new lines is really only implemented if you want to write more readable things). – Fatalize – 2018-07-30T06:43:42.080

@Fatalize Thanks, updated (finally!). I never thought about how inline predicate syntax is both a definition and predicate application, pretty cool. – sundar - Reinstate Monica – 2018-08-10T11:42:58.683

5

R, 89 79 bytes

function(m,y=apply(which(m>0,T),2,range)){y[!1/y]=0;m[y:y[2],y[3]:y[4],drop=F]}

Try it online!

Thanks to @ngm for the test cases code, and @J.Doe for saving 10 bytes !

  • I had to add drop=F parameter due to the default R behavior turning single row/col matrix into vectors...

digEmAll

Posted 2018-07-27T13:41:24.673

Reputation: 4 599

I didn't notice that my previous code was failing the all-zero cases... now it's fixed unfortunately with a lot more bytes :( – digEmAll – 2018-07-28T09:34:08.513

1I wish i could +2 this. Really nice use of fivenum. – JayCe – 2018-08-01T19:05:08.050

79 bytes using range and tweaking the indexation – J.Doe – 2018-10-03T15:36:44.110

1@J.Doe: range, of course ! great idea thanks ! – digEmAll – 2018-10-03T16:28:06.387

4

APL (Dyalog Classic), 17 15 bytes

{⍉⌽⍵⌿⍨∨\∨/×⍵}⍣4

Try it online!

ngn

Posted 2018-07-27T13:41:24.673

Reputation: 11 449

3

Wolfram Language (Mathematica), 66 bytes

If[Max@#>0,ImageCrop@Image[#~ArrayPad~1,r="Real"]~ImageData~r,{}]&

Try it online!

Now works by padding the array with zeroes (thanks @JungHwanMin)!

A second thanks to @JungHwanMin for saving 4 bytes

Beta Decay

Posted 2018-07-27T13:41:24.673

Reputation: 21 478

3

Python 2, 71 bytes

Returns by modifying the input. A list should be passed as input.

def f(a):exec'while a and 1>sum(a[-1]):a.pop()\na[:]=zip(*a)[::-1]\n'*4

Try it online!


Python 2, 77 bytes

This also modifies the input, but it works....

def f(a):exec'while a and 1>sum(a[-1]):a.pop()\na=zip(*a)[::-1]\n'*4;return a

Try it online!

user202729

Posted 2018-07-27T13:41:24.673

Reputation: 14 620

2

Python 2, 118 116 bytes

f=lambda a,n=4,s=sum:n and f(zip(*a[max(i for i in range(len(a))if s(s(a[:i],()))<1):][::-1]),n-1)or(s(s(a,()))>0)*a

Try it online!


Saved:

  • -2 bytes, thanks to shooqie

TFeld

Posted 2018-07-27T13:41:24.673

Reputation: 19 246

1You can save two bytes by assigning s=sum in lambda definition – shooqie – 2018-07-28T06:31:43.483

2

Jelly, 12 bytes

Ṗ§Ṫ¬ȧƲ¿UZµ4¡

Try it online!

As a function.

user202729

Posted 2018-07-27T13:41:24.673

Reputation: 14 620

2

Wolfram Language (Mathematica), 48 bytes

Nest[Reverse@Thread@#//.{{0..},a___}->{a}&,#,4]&

Try it online!

Doing it the normal way.

user202729

Posted 2018-07-27T13:41:24.673

Reputation: 14 620

Unfortunately \[Transpose] can't work here. – user202729 – 2018-07-27T16:18:18.510

2

K (ngn/k), 22 19 bytes

4{+|(+/&\~+/x)_'x}/

Try it online!

ngn

Posted 2018-07-27T13:41:24.673

Reputation: 11 449

2

Husk, 11 bytes

!5¡(T0mo↔↓¬

Try it online!

I feel like some bytes could be shaved off by shortening the !5¡ part.

How it works

!5¡(

Repeatedly apply the function explained below, collecting the results in an infinite list. Then, retrive the \$5^{\text{th}}\$ element. In other words, apply the function to the input 4 times.

mo↔↓¬

Map over the current version of the input and: reverse each, after having dropped the longest prefix consiting of zeroes only (dropping this prefix is performed by using Husk's , which is a function that crops the longest run of consecutive elements from the beginning of the list that yield truthy results when ran through a function, namely ¬, logical not).

T0

Transpose, replacing missing entries with 0.

Mr. Xcoder

Posted 2018-07-27T13:41:24.673

Reputation: 39 774

2

Retina, 87 bytes

/.\[(?!0,)/^+`\[0, 
[
/(?<! 0)]./^+`, 0]
]
\[(\[0(, 0)*], )+
[
(, \[0(, 0)*])+]|\[0]]
]

Try it online! Explanation:

/.\[(?!0,)/^+`

Until at least one row doesn't begin with zero...

\[0, 
[

... remove the leading zero from each row.

/(?<! 0)]./^+`

Until at least one row doesn't end with zero...

, 0]
]

... remove the trailing zero from each row.

\[(\[0(, 0)*], )+
[

Remove leading rows of zeros.

(, \[0(, 0)*])+]|\[0]]
]

Remove trailing rows of zeros, or the last remaining zero.

Neil

Posted 2018-07-27T13:41:24.673

Reputation: 95 035

1

@RickHitchcock It's format sensitive, add in the spaces: Try it online!

– Neil – 2018-07-27T21:21:43.993

2

Charcoal, 48 bytes

F⁴«W∧θ¬Σ§θ±¹Σ⊟θ¿θ≔⮌E§θ⁰E觧θνλθ»⪫[]⪫Eθ⪫[]⪫ι, ¦, 

Try it online! Link is to verbose version of code. Includes 15 bytes for formatting. Explanation:

F⁴«

Repeat 4 times.

W∧θ¬Σ§θ±¹

Repeat while the array is not empty but its last row sums to zero...

Σ⊟θ

Remove the last row from the array and print a line of the length of its sum, i.e. nothing.

¿θ≔⮌E§θ⁰E觧θνλθ»

If the array isn't empty then transpose it.

⪫[]⪫Eθ⪫[]⪫ι, ¦, 

Format the array nicely for display. (Standard output would be Iθ instead.)

Neil

Posted 2018-07-27T13:41:24.673

Reputation: 95 035

2

JavaScript, 144 140 129 127 bytes

w=>(t=w=>(q=(s=w=>w.some((r,j)=>r.find(e=>e,i=j))?w.slice(i).reverse():[[]])(s(w)))[0].map((e,j)=>q.map((e,i)=>q[i][j])))(t(w))

140 -> 129 bytes, thanks @Arnauld

Algorithm

  • Do twice:
    • Find first non-zero row
    • Slice off preceding rows
    • Reverse
    • Find first non-zero row
    • Slice off preceding rows
    • Reverse
    • Transpose

f = w=>(t=w=>(q=(s=w=>w.some((r,j)=>r.find(e=>e,i=j))?w.slice(i).reverse():[[]])(s(w)))[0].map((e,j)=>q.map((e,i)=>q[i][j])))(t(w));

w1 = [[0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0]];
w2 = [[0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0], [0, 5, 0, 0], [0, 0, 0, 0]];
w3 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
w4 = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

console.log(f(w1).join("\n"));
console.log(f(w2).join("\n"));
console.log(f(w3).join("\n"));
console.log(f(w4));

MattH

Posted 2018-07-27T13:41:24.673

Reputation: 171

You can save 7 bytes by using some/some instead of findIndex/find and rearranging the helper function declarations to get rid of the parenthesis around the (now single) main function argument.

– Arnauld – 2018-07-28T09:44:31.077

I think you can save 4 more bytes by having s return [[]] so that t is guaranteed to be able to operate on w[0].

– Arnauld – 2018-07-28T10:05:30.770

2

PHP (>=5.4), 200 194 186 184 bytes

(-6 bytes by returning null instead of empty array)

(-8 bytes thanks to Titus)

(-2 bytes with calling by reference thanks to Titus)

function R(&$a){$m=$n=1e9;foreach($a as$r=>$R)foreach($R as$c=>$C)if($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}for(;$m<=$M;)$o[]=array_slice($a[$m++],$n,$N-$n+1);$a=$o;}

Try it online!

How?

Finds min and max index for rows ($m & $M) and columns ($n & $N) and replaces the input with a sub array from $m,$n to $M,$N (this is a call by reference).

Night2

Posted 2018-07-27T13:41:24.673

Reputation: 5 484

Save 6 bytes with if($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;} – Titus – 2018-07-29T11:30:35.347

... and two bytes with while($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1); – Titus – 2018-07-29T11:34:08.913

@Titus: Thanks for the great tips. Loved the trick of using && and || and I'm sure I will be able to use that trick in other places as well. – Night2 – 2018-07-29T13:24:54.827

1You can save another two bytes with call by reference: $a= instead of return. – Titus – 2018-07-29T16:08:43.740

2

Ruby, 73 63 bytes

->a{4.times{_,*a=a while a[0]&.sum==0;a=a.reverse.transpose};a}

Try it online!

Edit: simplified, also the previous version crashed for all 0s

How it works:

  • do 4 times:
    • remove the first line while there is a first line and it's full of 0s
    • rotate the array clockwise by 90°
  • return the array

Asone Tuhid

Posted 2018-07-27T13:41:24.673

Reputation: 1 944

The link is correct, but your answer in the code block says &.sum<0 instead of &.sum<1. – Conor O'Brien – 2019-02-12T18:53:35.153

@ConorO'Brien my bad, new version didn't work for empty array (nil<1). Thanks for noticing anyway – Asone Tuhid – 2019-02-12T23:22:35.690

2

Octave, 48 49 bytes

@(a)sparse(1-min([x y v]=find(a))+x,1-min(y)+y,v)

Try it online!

Find nonzero points and rearrange them in a new sparse matrix.

rahnema1

Posted 2018-07-27T13:41:24.673

Reputation: 5 435

@alephalpha Answer updated! – rahnema1 – 2018-07-30T16:50:01.833

2

J, 24 bytes

(|.@|:@}.~0=+/@{.)^:4^:_

Try it online!

Explanation

(|.@|:@}.~0=+/@{.)^:4^:_
            +/                sum
              @               of
               {.             the first row
          0=                  is zero? (1 = true, 0 = false)
       }.~                    chop off that many rows from the front
 |.@|:@                       rotate by 90 deg (transpose then reverse)
(                )^:4         repeat this process 4 times (rotating a total of 360 deg)
                     ^:_      fixpoint - repeat until no change

Conor O'Brien

Posted 2018-07-27T13:41:24.673

Reputation: 36 228

1

Octave, 78 74 bytes

function x=f(x)
for k=1:nnz(~x)*4,x=rot90(x);x=x(:,~~cumsum(any(x,1)));end

Try it online!

Explanation

This rotates the matrix by 90 degrees (x=rot90(x)) a sufficient number of times (for k=1:... end). The number of rotations is a multiple of 4, so the final matrix has the original orientation. Specifically, the number of rotations is 4 times the number of zeros in the matrix (nnz(~x)*4).

For each rotation, if there are one or more columns on the left consisting of only zeros they are removed (x=x(:,~~cumsum(any(x,1)))).

What remains of the matrix after this process is output by the function (function x=f(x)).

Luis Mendo

Posted 2018-07-27T13:41:24.673

Reputation: 87 464

1

Japt -h, 23 11 bytes

4Æ=sUb_dà z

Try it


Explanation

                :Implicit input of 2D-array U
4Æ              :Map the range [0,4)
   s            :  Slice U from
    Ub          :   The first index in U where
      _dà      :    Any element is truthy (not zero)
          z     :  Rotate 90 degrees
  =             :  Reassign to U for the next iteration
                :Implicitly output the last element

Shaggy

Posted 2018-07-27T13:41:24.673

Reputation: 24 623

1

Attache, 40 bytes

Fixpoint[{Flip!_[N[0=Sum!_@0]...#_]}//4]

Try it online! Same business as below, just a bit smarter, splitting the process into four steps instead of two.

Alternatives

47 bytes: Fixpoint[{Reverse=>Tr!_[N[0=Sum!_@0]...#_]}//4]

48 bytes: Fixpoint[{MatrixRotate!_[N[0=Sum!_@0]...#_]}//4]


Attache, 68 bytes

Fixpoint[{n.=Dim@_@-1Tr[{_@1!in~-n'0or Sum!_@0}\Enumerate@_<:0]}//2]

Try it online!

Twice: This removes any first or last row whose sum is 0, then transposes the array. Then, this process is repeated until the result does not change.

Conor O'Brien

Posted 2018-07-27T13:41:24.673

Reputation: 36 228

1

Stax, 14 bytes

Ç·W≈y§╗♦º{¬║8•

Run and debug it

Alternative, also 14 bytes

Ç·W≈x≈ƒHq♣☻»íÅ

Run and debug it

wastl

Posted 2018-07-27T13:41:24.673

Reputation: 3 089

1

PHP, 188 bytes

function f(&$a){for($s=array_shift;!max($a[0]);)$s($a);for($p=array_pop;!max(end($a));)$p($a);for($w=array_walk;!max(($m=array_map)(reset,$a));)$w($a,$s);while(!max($m(end,$a)))$w($a,$p);}

call by reference.

breakdown

// call by reference
function f(&$a)
{
    // while first row is all zeroes, remove it
    while(!max($a[0]))array_shift($a);
    // while last row is all zeroes, remove it
    while(!max(end($a)))array_pop($a);
    // while first column is all zeroes, remove it
    while(!max(array_map(reset,$a)))array_walk($a,array_shift);
    // while last column is all zeroes, remove it
    while(!max(array_map(end,$a)))array_walk($a,array_pop);
}

Titus

Posted 2018-07-27T13:41:24.673

Reputation: 13 814

1

Clean, 73 bytes

import StdEnv,StdLib
$ =dropWhile(all((>)1))o reverse o transpose

$o$o$o$

Try it online!

Very similar to Laikoni's Haskell answer.

Οurous

Posted 2018-07-27T13:41:24.673

Reputation: 7 916

1

05AB1E (legacy), 13 bytes

2Fζ2FRDv¬O_i¦

Try it online or verify all test cases.

Explanation:

2F                    # Loop two times:
  ζ                   #  Zip/transpose; swapping rows/columns
                      #  (takes the input-matrix implicitly in the first iteration)
   2F                 #  Inner loop two times:
     R                #  Reverse the rows
      Dv              #  Inner loop over the rows:
        ¬             #   Get the first row (without popping the matrix)
         O_i          #   If the row consists only of 0s:
            ¦         #    Remove this first row from the matrix
                      # (output the result implicitly)

Kevin Cruijssen

Posted 2018-07-27T13:41:24.673

Reputation: 67 575

1The 2nd test case should output [[0, 0, 3], [0, 0, 0], [5, 0, 0]]. – Shaggy – 2018-10-28T21:58:30.753

@Shaggy Almost 5 months later, but it's fixed now (and 1 byte smaller in the process). xD – Kevin Cruijssen – 2019-02-12T14:08:22.903

1

Python 2, 86 bytes

lambda a,l=1:a if l>4else([a.pop()for b in a if sum(a[-1])<1],f(zip(*a[::-1]),l+1))[1]

Try it online!

Takes a list of lists, returns a list of tuples.

Explanation

Abuses the heck out of list comprehension. This is the equivalent expanded code:

def f(a,l=1):
    # after 4 rotations, the list is back in its original orientation, return
    if l > 4:
        return a
    else:
        # helper variable to store return values
        ret = []
        # "trim" all rows from "bottom" of list that only contain 0s
        # since we are always checking le that item in the list, don't need range(len(a))
        # since we are only removing at most one item per iteration, will never try to remove more than len(a) items
        # brackets surrounding generator force it to be consumed make a list, and therefore actually pop() list items
        ret.append([a.pop() for b in a if sum(a[-1]) < 1])
        # rotate the array, increase the number of rotations, and recursively call this function on the new array/counter
        ret.append(f(zip(*a[::-1]), l + 1)))
        # we only put both items in a list in order to stay in the one-line lambda format
        # discard the popped items and return the value from the recursive call
        return ret[1]

Triggernometry

Posted 2018-07-27T13:41:24.673

Reputation: 765