Entferne umgebende Nullen eines 2d Arrays

40

Dies ist eine zweidimensionale Version dieser Frage .

Bei einem nicht leeren zweidimensionalen Array / einer Matrix, die nur nicht negative ganze Zahlen enthält:

[0000000010000010011100000]

Das Array mit entfernten umgebenden Nullen ausgeben, dh das größte zusammenhängende Subarray ohne umgebende Nullen:

[010001111]

Beispiele:

[0000000010000010011100000][010001111]
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]]

[00000003000005000000][003000500]
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]]

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

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

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

Output:
[]

[000011110000][1111]
Input:
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]]

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

[010001000100][111]
Input:
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]

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

[111112311111][111112311111]
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
quelle
3
@MattH In einer nicht esoterischen Sprache ist nichts schwierig. :)Nur schwer, es kurz zu machen.
user202729
1
Können wir für den letzten Testfall eine falsche Ausgabe anstelle einer leeren Matrix angeben?
Sundar - Reinstate Monica
1
Wenn die Ausgabe eine nicht quadratische Matrix sein kann, fügen Sie bitte einen Testfall hinzu.
Sundar - Reinstate Monica
1
Ein Testfall, der meine frühere Vorlage brach: [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]](das Ergebnis hat eine Breite / Höhe von 1)
Conor O'Brien
1
Hey, es ist möglich, den Testfall
[111112311111]
Beta Decay

Antworten:

39

Wolfram Language (Mathematica) , 42 Byte

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

Probieren Sie es online!

Zelluläre Automaten sind in der Tat die Antwort auf das Leben , das Universum und alles . 1

Wie?

CellularAutomatonAkzeptiert ein Eingabearray und einen optionalen Hintergrundwert. Gibt daher an, {#,0}dass auf die Eingabe eine zellulare Automatenregel angewendet werden soll, vorausgesetzt, der Hintergrund ist 0s.

Eine nette Sache hier ist, dass CellularAutomatondie Ausgabe so beschnitten wird, dass kein Rand von Hintergrundzellen vorhanden ist (da die Ausgabe ansonsten auf einer unendlichen Ebene liegt).

Der Code wendet die Regel {Null, {}, {0, 0}}- Anwenden des Kopfes Nullauf den 0-Radius-Nachbarn jeder Zelle (dh nur die Mitte: die Zelle selbst) - genau zu den angegebenen 0Zeiten an. Das Ergebnis ist die ursprüngliche Eingabe, wobei jedoch der Hintergrund entfernt wird (dh die umgebenden 0s werden abgeschnitten ).


1. Sehen Sie die Bytecount meiner Antwort? ;)

JungHwan min
quelle
6
Netter eingebauter Missbrauch ... naja Mathematica hat einen eingebauten, nur nicht direkt belichteten.
User202729
3
Keine XKCD 505 Referenz?
Esolanging Fruit
+1 für zellulare Automaten und die ultimative Antwort.
Hochradioaktiv
14

JavaScript (ES6), 98 Byte

(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)

Probieren Sie es online!

Wie?

Um das Fehlen einer integrierten Zip -Funktion zu umgehen , definieren wir eine Funktion g () , die abhängig vom Wert des globalen Flags z entweder auf die Zeilen oder auf die Spalten der Eingabematrix a [] angewendet werden kann .

g () sucht nach dem minimalen Index m und dem maximalen Index M von entweder nicht leeren Zeilen (wenn z undefiniert ist) oder nicht leeren Spalten (wenn z definiert ist) und gibt das entsprechende Segment entweder der Matrix selbst oder einer gegebenen Zeile zurück der Matrix.

Zusammenfassen:

  • Wir entfernen zuerst Zeilen, indem wir g () in der Matrix mit z undefined aufrufen
  • Wir entfernen dann Spalten, indem wir g () für jede Zeile mit definiertem z aufrufen , was zu diesem eher ungewöhnlichen Ergebnis führt.map(z=g)

Kommentiert

(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
quelle
2
Das ist beeindruckend.
Jack Hales
3
@Jek, Arnauld lebt in einer ganz anderen Dimension. Aber wenn Sie sehr glücklich, kann man gelegentlich einen Trick finden , dass er eine kürzere Lösung verpasst und veröffentlichen. Dabei entwickeln Sie ein sehr tiefes Verständnis von JavaScript.
Rick Hitchcock
4
@RickHitchcock Ich bin nicht so gut in der Erkennung von Codemustern und es fehlen mir regelmäßig viele Dinge, auch wenn ich sie schon einmal gesehen habe. In diesem Beispiel habe ich mich auf die Wiederverwendbarkeit von g () konzentriert und eine offensichtliche Optimierung für die Aktualisierung von m und M (-9 Byte) verpasst . Ich stimme voll und ganz zu, dass Code-Golf eine großartige (und unterhaltsame) Möglichkeit ist, viel über die Feinheiten einer Sprache zu lernen.
Arnauld
7

Haskell , 62 61 Bytes

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

Probieren Sie es online!

foldr(zipWith(:))ewith e=[]:eist etwas kürzertranspose und snd.span(all(<1))löscht führende Nullen aus einer Liste von Listen. Wie transposefolgt, reverseentspricht eine 2D-Liste einer Drehung um 90 °, der Code f.f.f.fist nur vier Mal , wenn führende Listen von Nullen gelöscht und gedreht werden .

Laikoni
quelle
5

Brachylog , 24 22 20 19 Bytes

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

Probieren Sie es online!

Gibt die Ergebnismatrix als Array von Arrays aus oder false für leere Ausgaben.

(Dank an @Fatalize für das Vorschlagen eines Inline-Prädikats und das Speichern von 1 Byte.)

Erläuterung

Prädikat 0 (Haupt):

{...}     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

Prädikat 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 - Setzen Sie Monica wieder ein
quelle
Schreiben des ersten Prädikats inline ist 1 Byte kürzer: {s.h+>0∧.t+>0∧}\↰₁\ . (Dies gilt für so ziemlich jede Brachylog-Antwort. Prädikate in neuen Zeilen werden nur dann implementiert, wenn Sie lesbarere Dinge schreiben möchten.)
Fatalize
@Fatalize Danke, aktualisiert (endlich!). Ich habe nie darüber nachgedacht, wie Inline-Prädikatsyntax sowohl eine Definitions- als auch eine Prädikatsanwendung ist, ziemlich cool.
Sundar - Wiedereinsetzung von Monica
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)

Probieren Sie es online!

Der ~Helfer nimmt einen nicht negativen Vektor und gibt einen Vektor mit FALSEfür das "Äußere" 0des Vektors und TRUEfür Positive und alle "Inneren" zurück 0. Diese Funktion wird auf die Zeilen- und Spaltensummen der Eingabematrix angewendet.

~und ! Rs Parser-Behandlung von Operatoren verwenden.

Korrigiert gemäß @ DigEmAlls Kommentar, aber mit einigen Bytes, die von @ J.Doe zurückgespielt wurden

ngm
quelle
1
Ich denke, Sie sollten hinzufügen, drop=Fwie ich es getan habe, sonst geben diese 2 Tests einen Vektor anstelle von Zeile und Spalte zurück: Versuchen Sie es online!
digEmAll
97 Bytes mit drop=F. Immer noch unter einer Tonne!
J.Doe
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]}

Probieren Sie es online!

Vielen Dank an @ngm für den Testfallcode und @ J.Doe für das Speichern von 10 Bytes!

  • Ich musste drop=FParameter hinzufügen , da das Standardverhalten von R die Matrix aus einer Zeile / Spalte in Vektoren umwandelt ...
digEmAll
quelle
Ich habe nicht bemerkt, dass mein vorheriger Code die Null-Fälle nicht
erfüllt hat
1
Ich wünschte, ich könnte das +2. Wirklich schöne Verwendung von Fivenum.
JayCe
79 Bytes mit rangeund Optimierung der Indexierung
J.Doe
1
@ J.Doe: Reichweite natürlich! tolle idee danke!
digEmAll
3

Python 2 , 71 Bytes

Kehrt durch Ändern der Eingabe zurück. Eine Liste sollte als Eingabe übergeben werden.

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

Probieren Sie es online!


Python 2 , 77 Bytes

Dies ändert auch die Eingabe, aber es funktioniert ....

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

Probieren Sie es online!

user202729
quelle
3

Wolfram Language (Mathematica) , 66 Bytes

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

Probieren Sie es online!

Jetzt funktioniert das Auffüllen des Arrays mit Nullen (danke @JungHwanMin)!

Ein zweites Dankeschön an @JungHwanMin für die Einsparung von 4 Bytes

Beta-Zerfall
quelle
2

Schale , 11 Bytes

!5¡(T0mo↔↓¬

Probieren Sie es online!

Ich habe das Gefühl, dass einige Bytes durch Kürzen des !5¡Teils abgeschabt werden könnten .

Wie es funktioniert

!5¡(

5th

mo↔↓¬

Karte die aktuelle Version des Eingangs über und: jede Rückwärts nach dem längsten Präfix fallen gelassen, die nur aus Nullen consiting (dieses Präfix dropping durch Verwendung Husk der durchgeführt wird , das ist eine Funktion , die den längsten Lauf aufeinander folgender Elemente von Beginn der Ernte Liste, die wahrheitsgemäße Ergebnisse liefert, wenn eine Funktion durchlaufen wird, nämlich ¬logisch nicht).

T0

Transponieren, fehlende Einträge durch 0 ersetzen .

Mr. Xcoder
quelle
2

Retina , 87 Bytes

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

Probieren Sie es online! Erläuterung:

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

Bis mindestens eine Zeile nicht mit Null beginnt ...

\[0, 
[

... entfernen Sie die führende Null aus jeder Zeile.

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

Bis mindestens eine Zeile nicht mit Null endet ...

, 0]
]

... entfernen Sie die nachstehende Null aus jeder Zeile.

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

Entfernen Sie führende Nullzeilen.

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

Entfernen Sie nachfolgende Nullzeilen oder die letzte verbleibende Null.

Neil
quelle
1
@ RickHitchcock Es ist formatabhängig, fügen Sie die Leerzeichen hinzu: Probieren Sie es online!
Neil
2

Kohle , 48 Bytes

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

Probieren Sie es online! Link ist eine ausführliche Version des Codes. Beinhaltet 15 Bytes für die Formatierung. Erläuterung:

F⁴«

4 mal wiederholen.

W∧θ¬Σ§θ±¹

Wiederholen, solange das Array nicht leer ist, aber die letzte Zeile auf Null summiert ...

Σ⊟θ

Entfernen Sie die letzte Zeile aus dem Array und drucken Sie eine Zeile der Länge seiner Summe, dh nichts.

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

Wenn das Array nicht leer ist, transponieren Sie es.

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

Formatieren Sie das Array gut für die Anzeige. (Standardausgabe wäre Iθstattdessen.)

Neil
quelle
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, danke @Arnauld

Algorithmus

  • Zweimal machen:
    • Finden Sie die erste Zeile ungleich Null
    • Vorangehende Reihen abschneiden
    • Umkehren
    • Finden Sie die erste Zeile ungleich Null
    • Vorangehende Reihen abschneiden
    • Umkehren
    • Transponieren

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
quelle
Sie können 7 Bytes einsparen, indem Sie some/someanstelle der findIndex/findHilfsfunktionsdeklarationen die Klammern um das (jetzt einzelne) Hauptfunktionsargument verwenden und neu anordnen.
Arnauld
Ich denke, Sie können 4 weitere Bytes sparen, indem Sie s return haben, [[]]damit t garantiert in der Lage ist, damit zu arbeiten w[0].
Arnauld
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

Probieren Sie es online!


Gerettet:

  • -2 Bytes dank shooqie
TFeld
quelle
1
Sie können zwei Bytes speichern, indem Sie s=sumin Lambda-Definition
zuweisen
2

PHP (> = 5,4), 200 194 186 184 Bytes

(-6 Bytes durch Rückgabe nullanstelle eines leeren Arrays)

(-8 Bytes dank Titus )

(-2 Bytes mit Referenzaufruf dank 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;}

Probieren Sie es online!

Wie?

Findet den Min- und Max-Index für Zeilen ( $m& $M) und Spalten ( $n& $N) und ersetzt die Eingabe durch ein Sub-Array von $m,$nbis $M,$N(dies ist ein Referenzaufruf).

Night2
quelle
Speichern Sie 6 Bytes mitif($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}
Titus
... und zwei Bytes mitwhile($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1);
Titus
@Titus: Danke für die tollen Tipps. Liebte den Trick mit &&und ||und ich bin mir sicher, dass ich diesen Trick auch an anderen Orten anwenden kann.
Night2
1
Sie können mit call by reference weitere zwei Bytes speichern: $a=statt return.
Titus
2

Oktave, 48 49 Bytes

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

Probieren Sie es online!

Finden Sie Punkte ungleich Null und ordnen Sie sie in einer neuen dünnen Matrix neu an.

rahnema1
quelle
@alephalpha Antwort aktualisiert!
Rahnema1
2

J , 24 Bytes

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

Probieren Sie es online!

Erläuterung

(|.@|:@}.~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
quelle
2

Ruby , 73 63 Bytes

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

Probieren Sie es online!

Edit: vereinfacht, auch die Vorgängerversion stürzte für alle 0s ab

Wie es funktioniert:

  • mache 4 mal:
    • entferne die erste Zeile, während es eine erste Zeile gibt und sie voller 0s ist
    • Drehen Sie das Array im Uhrzeigersinn um 90 °
  • Array zurückgeben
Asone Tuhid
quelle
Der Link ist korrekt, aber Ihre Antwort im Codeblock lautet &.sum<0statt&.sum<1 .
Conor O'Brien
@ ConorO'Brien meine schlechte, neue Version funktionierte nicht für leeres Array (nil <1). Vielen Dank, dass Sie es trotzdem bemerkt haben
Asone Tuhid
1

Oktave , 78 74 Bytes

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

Probieren Sie es online!

Erläuterung

Dadurch wird die Matrix ausreichend oft um 90Grad ( x=rot90(x)) gedreht ( for k=1:... end). Die Anzahl der Umdrehungen ist ein Vielfaches von 4, sodass die endgültige Matrix die ursprüngliche Ausrichtung aufweist. Insbesondere entspricht die Anzahl der Umdrehungen 4der Anzahl der Nullen in der Matrix ( nnz(~x)*4).

Wenn sich links für jede Drehung eine oder mehrere Spalten befinden, die nur aus Nullen bestehen, werden diese entfernt ( x=x(:,~~cumsum(any(x,1)))).

Was nach diesem Vorgang von der Matrix übrig bleibt, wird von der Funktion ( function x=f(x)) ausgegeben .

Luis Mendo
quelle
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);}

Anruf durch Hinweis.

Nervenzusammenbruch

// 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
quelle
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]

Probieren Sie es online!

Nimmt eine Liste von Listen auf und gibt eine Liste von Tupeln zurück.

Erläuterung

Missbräuchlich zum Teufel aus dem Listenverständnis. Dies ist der entsprechende erweiterte 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]
Triggernometrie
quelle
1

Japt -h , 23 11 Bytes

4Æ=sUb_dà z

Versuch es


Erläuterung

                :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
Zottelig
quelle