Rimuovere gli zero circostanti di un array 2d


40

Questa è una versione bidimensionale di questa domanda .

Dato un array / matrice bidimensionale non vuoto contenente solo numeri interi non negativi:

[0000000010000010011100000]

Output dell'array con gli zero circostanti rimossi, ovvero il più grande subarray contiguo senza zero circostante:

[010001111]

Esempi:

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

3
@MattH Niente è difficile in un linguaggio non esoterico. :)Solo difficile farla breve.
user202729

1
Possiamo dare un risultato falso invece di una matrice vuota, per l'ultimo caso di test?
Sundar - Ripristina Monica il

1
Inoltre, se l'output può essere una matrice non quadrata, aggiungere un caso di test per questo.
Sundar - Ripristina Monica il

1
Un caso di prova che ha rotto la mia precedente presentazione: [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]](il risultato ha una larghezza / altezza di 1)
Conor O'Brien,

1
Ehi, è possibile aggiungere il test case
[111112311111]
Decadimento beta

Risposte:



39

Wolfram Language (Mathematica) , 42 byte

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

Provalo online!

Gli automi cellulari sono davvero la risposta alla vita , all'universo e a tutto . 1

Come?

CellularAutomatonaccetta un array di input e un valore di sfondo opzionale. Pertanto, {#,0}specifica che una regola di automa cellulare deve essere applicata all'input, assumendo uno sfondo di 0s.

Una cosa chiara qui è che CellularAutomatonritaglia l'output in modo che non sia presente alcun bordo di celle di sfondo (perché altrimenti l'output si trova su un piano infinito).

Il codice applica la regola {Null, {}, {0, 0}}- applicando la testa Nullal vicino di raggio 0 di ogni cella (cioè solo il centro: la cella stessa) - esattamente i 0tempi. Il risultato di questo è l'input originale, ma con lo sfondo rimosso (cioè ritagliando le 0s circostanti ).


1. Vedi il resoconto della mia risposta? ;)


6
Bello abuso incorporato ... beh, Mathematica ha un built-in, semplicemente non esposto direttamente.
user202729,

3
Nessun riferimento XKCD 505 ?
Esolanging Fruit,

+1 per gli automi cellulari e la risposta definitiva.
Altamente radioattivo il

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)

Provalo online!

Come?

Per ovviare alla mancanza di uno zip incorporato, definiamo una funzione g () che è in grado di operare sulle righe o sulle colonne della matrice di input a [] , a seconda del valore della bandiera globale z .

g () cerca l'indice minimo me l'indice massimo M di righe non vuote (se z non è definito) o di colonne non vuote (se z è definito) e restituisce la porzione corrispondentedella matrice stessa o di una determinata riga della matrice.

Riassumere:

  • per prima cosa rimuoviamo le righe invocando g () sulla matrice con z non definito
  • quindi rimuoviamo le colonne invocando g () su ogni riga con z definito, il che porta a questo piuttosto insolito.map(z=g)

Commentate

(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

2
Questo è impressionante.
Jack Hales,

3
@Jek, Arnauld vive in una dimensione completamente diversa. Ma se sei estremamente fortunato, a volte puoi trovare un trucco che gli è sfuggito e pubblicare una soluzione più breve. Nel processo, svilupperai una comprensione molto profonda di JavaScript.
Rick Hitchcock,

4
@RickHitchcock Non sono così bravo nel riconoscimento del modello di codice e mi mancano regolarmente molte cose, anche se le ho già viste prima. In questo esempio particolare, mi sono concentrato sulla riusabilità di g () e ho perso un'ottimizzazione abbastanza ovvia sul modo di aggiornare m e M (-9 byte). Concordo pienamente sul fatto che il golf di codice sia un ottimo (e divertente) modo per imparare molto sulle sottigliezze di una lingua.
Arnauld,

7

Haskell , 62 61 byte

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

Provalo online!

foldr(zipWith(:))econ e=[]:eè leggermente più brevetranspose e snd.span(all(<1))elimina le principali liste di zeri da una lista di liste. Come transposeseguito da reverseun elenco 2D equivale a una rotazione di 90 °, il codice f.f.f.fè solo quattro volte rilasciare gli elenchi principali di zeri e ruotare .




5

Brachylog , 24 22 20 19 byte

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

Provalo online!

Emette la matrice dei risultati come una matrice di array o false per l'output vuoto.

(Grazie a @Fatalize per aver suggerito predicato inline e aver salvato 1 byte.)

Spiegazione

Predicato 0 (principale):

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

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

Scrivere la prima linea predicato è 1 byte più breve: {s.h+>0∧.t+>0∧}\↰₁\ . (Questo è vero per quasi tutte le risposte a Brachylog, i predicati su nuove righe sono implementati solo se vuoi scrivere cose più leggibili).
Fatalizza il

@Fatalize Grazie, aggiornato (finalmente!). Non ho mai pensato a come la sintassi del predicato inline sia un'applicazione di definizione e predicato, piuttosto interessante.
Sundar - Ripristina Monica il

5

R , 96 100 97 byte

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

Provalo online!

L' ~helper prende un vettore non negativo e restituisce un vettore FALSEper gli "esterni" 0del vettore e TRUEper i positivi e qualsiasi "interno"0 . Questa funzione viene applicata alle somme di riga e colonna della matrice di input.

~ e ! utilizzare il trattamento parser di R per gli operatori.

Corretto secondo il commento di @ DigEmAll, ma con alcuni byte restituito da @ J.Doe


1
Penso che dovresti aggiungere drop=Fcome ho fatto, altrimenti questi 2 test restituiranno un vettore anziché riga e colonna: provalo online!
digEmAll

97 byte con drop=F. Ancora sotto una tonnellata!
J.Doe,

5

R , 89 79 byte

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

Provalo online!

Grazie a @ngm per il codice dei casi di test e @ J.Doe per aver salvato 10 byte!

  • Ho dovuto aggiungere un drop=Fparametro a causa del comportamento R predefinito trasformando la matrice singola riga / col in vettori ...

Non ho notato che il mio codice precedente non andava a buon fine nei casi zero ... ora, purtroppo, è stato corretto con molti più byte :(
digEmAll

1
Vorrei poterlo fare +2. Uso davvero bello del fivenum.
JayCe,

79 byte usando rangee modificando l'indicizzazione
J.Doe

1
@ J.Doe: gamma, ovviamente! ottima idea grazie!
digEmAll


3

Python 2 , 71 byte

Ritorna modificando l'ingresso. Un elenco deve essere passato come input.

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

Provalo online!


Python 2 , 77 byte

Questo modifica anche l'input, ma funziona ....

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

Provalo online!





2

Buccia , 11 byte

!5¡(T0mo↔↓¬

Provalo online!

Sento che alcuni byte potrebbero essere eliminati accorciando la !5¡parte.

Come funziona

!5¡(

Applicare ripetutamente la funzione spiegata di seguito, raccogliendo i risultati in un elenco infinito. Quindi, riavvia il file5esimoelemento. In altre parole, applicare la funzione all'ingresso 4 volte.

mo↔↓¬

Esegui il mapping sulla versione corrente dell'input e: inverti ciascuno, dopo aver eliminato il prefisso più lungo che comprende solo zeri (l'eliminazione di questo prefisso viene eseguita utilizzando Husk's , che è una funzione che ritaglia il ciclo più lungo di elementi consecutivi dall'inizio del elenco che produce risultati veritieri quando viene eseguita una funzione, vale a dire ¬, logicamente no).

T0

Trasponi, sostituendo le voci mancanti con 0 .


2

Retina , 87 byte

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

Provalo online! Spiegazione:

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

Fino a quando almeno una riga non inizia con zero ...

\[0, 
[

... rimuove lo zero iniziale da ogni riga.

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

Fino a quando almeno una riga non termina con zero ...

, 0]
]

... rimuove lo zero finale da ogni riga.

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

Rimuovi le righe iniziali di zeri.

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

Rimuovi le righe finali di zeri o l'ultimo zero rimanente.


1
@RickHitchcock È sensibile al formato, aggiungi gli spazi: provalo online!
Neil,

2

Carbone , 48 byte

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

Provalo online! Il collegamento è alla versione dettagliata del codice. Include 15 byte per la formattazione. Spiegazione:

F⁴«

Ripeti 4 volte.

W∧θ¬Σ§θ±¹

Ripeti mentre l'array non è vuoto ma la sua ultima riga si somma a zero ...

Σ⊟θ

Rimuovere l'ultima riga dall'array e stampare una riga della lunghezza della sua somma, ovvero nulla.

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

Se l'array non è vuoto, trasporlo.

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

Formatta bene l'array per la visualizzazione. (L'output standard sarebbe Iθinvece.)


2

JavaScript, 144 140 129 127 byte

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 byte, grazie @Arnauld

Algoritmo

  • Fare due volte:
    • Trova la prima riga diversa da zero
    • Tagliare le file precedenti
    • Inverso
    • Trova la prima riga diversa da zero
    • Tagliare le file precedenti
    • Inverso
    • Trasporre

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


Puoi salvare 7 byte usando some/someinvece di findIndex/findriordinare le dichiarazioni della funzione di supporto per eliminare la parentesi attorno all'argomento (ora singolo) della funzione principale.
Arnauld,

Io penso che è possibile salvare più di 4 byte avendo s ritorno [[]]in modo che t è garantito per essere in grado di operare su w[0].
Arnauld,

2

Python 2 , 118 116 byte

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

Provalo online!


Salvato:

  • -2 byte, grazie a shooqie

1
È possibile salvare due byte assegnando s=sumnella definizione lambda
shooqie il

2

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

(-6 byte restituendo nullinvece di array vuoto)

(-8 byte grazie a Titus )

(-2 byte con chiamata per riferimento grazie a 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;}

Provalo online!

Come?

Trova l'indice min e max per le righe ( $m& $M) e le colonne ( $n& $N) e sostituisce l'input con un array secondario da $m,$na $M,$N(questa è una chiamata per riferimento).


Salva 6 byte conif($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}
Titus

... e due byte conwhile($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1);
Tito il

@Titus: grazie per gli ottimi consigli. Mi è piaciuto molto il trucco dell'uso &&e ||sono sicuro che sarò in grado di usare quel trucco anche in altri luoghi.
Night2

1
È possibile salvare altri due byte con la chiamata per riferimento: $a=anziché return.
Tito

2

Ottava, 48 49 byte

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

Provalo online!

Trova punti diversi da zero e riorganizzali in una nuova matrice sparsa.


@alephalpha Risposta aggiornata!
rahnema1,


2

J , 24 byte

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

Provalo online!

Spiegazione

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

2

Rubino , 73 63 byte

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

Provalo online!

Modifica: semplificato, anche la versione precedente è andata in crash per tutti 0 s

Come funziona:

  • fare 4 volte:
    • rimuovere la prima riga mentre è presente una prima ed è piena di 0s
    • ruotare l'array in senso orario di 90 °
  • restituisce l'array

Il collegamento è corretto, ma la tua risposta nel blocco di codice dice &.sum<0invece di &.sum<1.
Conor O'Brien,

@ ConorO'Brien il mio cattivo, la nuova versione non ha funzionato per array vuoto (zero <1). Grazie per
avermelo

1

Ottava , 78 74 byte

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

Provalo online!

Spiegazione

Questo ruota la matrice di 90gradi ( x=rot90(x)) un numero sufficiente di volte ( for k=1:... end). Il numero di rotazioni è un multiplo di 4, quindi la matrice finale ha l'orientamento originale. In particolare, il numero di rotazioni è 4volte il numero di zeri nella matrice ( nnz(~x)*4).

Per ogni rotazione, se ci sono una o più colonne sulla sinistra costituite solo da zeri, vengono rimosse ( x=x(:,~~cumsum(any(x,1)))).

Ciò che rimane della matrice dopo questo processo viene emesso dalla funzione ( function x=f(x)).



1

PHP, 188 byte

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);}

chiamare per riferimento.

abbattersi

// 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);
}


1

Python 2 , 86 byte

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]

Provalo online!

Prende un elenco di elenchi, restituisce un elenco di tuple.

Spiegazione

Abusa della comprensione fuori dalla lista. Questo è il codice espanso equivalente:

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]

1

Japt -h , 23 11 byte

4Æ=sUb_dà z

Provalo


Spiegazione

                :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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.