2D配列の周囲のゼロを削除する


40

これは、この質問の 2次元バージョンです。

負でない整数のみを含む空でない2次元の配列/行列が与えられた場合:

[0000000010000010011100000]

周囲のゼロを削除した配列、つまり周囲のゼロを含まない最大の連続部分配列を出力します。

[010001111]

例:

[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非難解な言語では難しいことは何もありません。:)短くするのは難しい。
user202729

1
最後のテストケースでは、空の行列の代わりに偽の出力を提供できますか?
スンダ-復活モニカ

1
また、出力が非正方行列になる可能性がある場合は、そのためのテストケースを追加してください。
スンダ

1
以前の提出を中断したテストケース:([[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]]結果の幅/高さは1
Conor O'Brien

1
ちょっと、テストケースを追加することは可能ですか
[111112311111]
ベータディケイ

回答:



39

Wolfram言語(Mathematica)、42バイト

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

オンラインでお試しください!

セルオートマトンは、実際、生命宇宙すべてに対する答えです。1

どうやって?

CellularAutomaton入力配列とオプションの背景値を受け入れます。したがって、{#,0}背景が0s であると仮定して、セルオートマトンルールを入力に適用する必要があることを指定します。

ここでのすてきなことはCellularAutomaton、バックグラウンドセルの境界が存在しないように出力をトリミングすることです(そうでない場合、出力は無限平面上にあるため)。

コードはルールを適用します{Null, {}, {0, 0}}- Null各セルの0半径の隣にヘッドを適用します(つまり、中心のみ:セル自体)-正確に数0回。この結果は元の入力ですが、背景が削除されています(つまり、周囲0のsを切り取ります)。


1.回答のバイト数を確認しますか?;)


6
組み込みの悪用... Mathematicaには組み込み機能があり、直接公開されていません。
user202729


セルラーオートマトンと究極の回答のための+1。
高放射能

14

JavaScript(ES6)、98バイト

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

オンラインでお試しください!

どうやって?

zipビルトインの欠如を克服するために、グローバルフラグzの値に応じて、入力行列a []の行または列のいずれかを操作できる関数g()を定義します。

g()は、空でない行( zが未定義の場合)または空でない列( zが定義されている場合)の最小インデックス mおよび最大インデックス Mを探し、マトリックス自体または指定された行の対応するスライスを返しますマトリックスの。

要約する:

  • まず、未定義のzを使用して行列でg()を呼び出して行を削除します
  • 次に、zが定義されている各行でg()を呼び出して列を削除します。.map(z=g)

コメント済み

(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
それは印象的です。
ジャック・ヘイルズ

3
@Jek、アーナウルドは全く異なる次元に住んでいます。しかし、あなたが非常に幸運なら、彼が見逃したトリックを時々見つけて、より短い解決策を投稿することができます。その過程で、JavaScriptについて非常に深い理解を深めることができます。
リックヒッチコック

4
@RickHitchcockコードパターンの認識がそれほど得意ではないので、以前見たことがあっても、定期的に多くのことを見逃しています。この特定の例では、g()の再利用性に焦点を当てており、mおよびM(-9バイト)を更新する方法についての明らかな最適化を見逃していました。コードゴルフは言語の微妙さについて多くを学ぶための素晴らしい(そして楽しい)方法であることに完全に同意します。
アーナルド

7

Haskell62 61バイト

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

オンラインでお試しください!

foldr(zipWith(:))ewith e=[]:eわずかに短くtransposesnd.span(all(<1))リストのリストからゼロの先行リストを削除します。以下のようにtranspose続くreverse90によって回転に等しい2Dリスト上°、コードはf.f.f.fわずか4倍である零点と回転の主要リストをドロップ




5

Brachylog24 22 20 19バイト

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

オンラインでお試しください!

結果行列を配列の配列として出力します。空の出力の場合はfalseを出力します。

(インライン述語を提案し、1バイトを節約してくれた@Fatalizeに感謝します。)

説明

述語0(メイン):

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

述語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)

最初の述部をインラインで記述すると、1バイト短くなります{s.h+>0∧.t+>0∧}\↰₁\ 。(これは、ほとんどすべてのBrachylog回答に当てはまります。新しい行の述部は、より読みやすいものを書きたい場合にのみ実装されます)。
18

@Fatalizeありがとう、更新(最終的に!)。インライン述語構文が定義と述語アプリケーションの両方であるとは考えていませんでした。
スンダ

5

R96100 97バイト

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

オンラインでお試しください!

~ヘルパーは非負ベクトルを取り、とのベクトルを返しますFALSE「外部」のため0のベクトルのとTRUE陽性と任意の「インテリア」のため0の。この関数は、入力行列の行と列の合計に適用されます。

~及び! 事業者のRのパーサ処理を使用しています。

@DigEmAllのコメントに従って修正されましたが、@ J.Doeから返されたいくつかのバイトがあります


1
私がしたように追加する必要があると思いますdrop=F、そうでなければ、これらの2つのテストは行と列の代わりにベクトルを返します:オンラインで試してみてください!
digEmAll

97はバイトdrop=F。まだトン以下!
J.Doe

5

R89 79バイト

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

オンラインでお試しください!

テストケースのコードを作成してくれた@ngmと、10バイトを保存してくれた@ J.Doeに感謝します!

  • drop=F単一の行/列行列をベクトルに変換するデフォルトのR動作のためにパラメータを追加する必要がありました...

私の以前のコードがすべてゼロの場合に失敗していたことに気づきませんでした...今では残念ながら多くのバイトで修正されています:(
digEmAll

1
これが+2できたらいいのに。fivenumの本当にいい使い方。
JayCe

rangeインデックスを使用して調整する79バイト
-J.Doe

1
@ J.Doe:範囲、もちろん!素晴らしいアイデアありがとう!
digEmAll






2

、11バイト

!5¡(T0mo↔↓¬

オンラインでお試しください!

!5¡部品を短くすることでいくつかのバイトを削ることができるように感じます。

使い方

!5¡(

5番目

mo↔↓¬

入力の現在のバージョンをマッピングし、ゼロのみからなる最長のプレフィックスを削除した後、それぞれを反転します(このプレフィックスの削除は、Husk'sを使用して実行されます。これは、関数を実行したときに真実の結果が得られるリスト、つまり¬論理的でない)。

T0

転置し、欠落しているエントリを0に置き換えます。


2

網膜、87バイト

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

オンラインでお試しください!説明:

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

少なくとも1行がゼロで始まらないまで...

\[0, 
[

...各行から先行ゼロを削除します。

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

少なくとも1行がゼロで終了しないまで...

, 0]
]

...各行から末尾のゼロを削除します。

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

ゼロの先頭行を削除します。

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

ゼロの最後の行、または最後の残りのゼロを削除します。


1
@RickHitchcockフォーマットに敏感なので、スペースを追加してください
ニール

2

、48バイト

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

オンラインでお試しください!リンクは、コードの詳細バージョンです。フォーマット用に15バイトが含まれています。説明:

F⁴«

4回繰り返します。

W∧θ¬Σ§θ±¹

配列が空ではないが、最後の行の合計がゼロになるまで繰り返します...

Σ⊟θ

配列から最後の行を削除し、その合計の長さの行、つまり何も印刷しません。

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

配列が空でない場合は、転置します。

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

表示用に配列を適切にフォーマットします。(標準出力はIθ代わりになります。)


2

JavaScript、144 140 129 127バイト

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バイト、@ Arnauldに感謝

アルゴリズム

  • 2回行う:
    • 最初の非ゼロ行を検索
    • 前の行を切り取る
    • 最初の非ゼロ行を検索
    • 前の行を切り取る
    • 転置

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


ヘルパー関数宣言の代わりに使用して再配置し、(現在は単一の)メイン関数引数の括弧を取り除くことにより、7バイト節約できます。some/somefindIndex/find
アーナウルド

私が考えるあなたができる4つの以上のバイトを保存することによってsのリターン[[]]ように、tは上で動作することができるように保証されますw[0]
アーナルド


2

PHP(> = 5.4)、200 194 186 184バイト

null空の配列の代わりに返すことにより-6バイト)

Titusのおかげで8バイト)

Titusのおかげで参照による呼び出しで2バイト)

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

オンラインでお試しください!

どうやって?

行($m$M)および列($n$N)の最小および最大インデックスを検索し、入力を$m,$nto からのサブ配列に置き換えます$M,$N(これは参照による呼び出しです)。


で6つのバイトを保存if($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}
タイタス

...と2バイトwhile($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1);
Titus

@タイタス:素晴らしいヒントをありがとう。使用してのトリックを愛した&&||、私は確信して、私はだけでなく、他の場所でそのトリックを使用することができますよ。
Night2

1
あなたは、参照することにより、コールして、別の2つのバイトを保存することができます:$a=代わりにreturn
タイタス



2

J、24バイト

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

オンラインでお試しください!

説明

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

ルビー73 63バイト

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

オンラインでお試しください!

編集:簡素化、すべて0のsで以前のバージョンがクラッシュしました

使い方:

  • 4回行う:
    • 最初の行があり、0sでいっぱいの間に最初の行を削除する
    • 配列を時計回りに90°回転させます
  • 配列を返します

リンクは正しいですが、コードブロックでの答えはの&.sum<0代わりに表示され&.sum<1ます。
コナーオブライエン

@ ConorO'Brien私の悪い、新しいバージョンは空の配列では機能しませんでした(nil <1)。とにかく気付いてくれてありがとう
Asone Tuhid

1

オクターブ78 74バイト

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

オンラインでお試しください!

説明

これにより、マトリックスが十分な回数90x=rot90(x))度だけ回転しfor k=1:... endます()。回転数はの倍数で4あるため、最終的なマトリックスは元の方向になります。具体的には、回転4数は行列のゼロの数(nnz(~x)*4)倍です。

回転ごとに、左側にゼロのみで構成される1つ以上の列がある場合、それらは削除されます(x=x(:,~~cumsum(any(x,1))))。

このプロセス後にマトリックスに残るものは、関数(function x=f(x))によって出力されます。



1

PHP、188バイト

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
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バイト

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]

オンラインでお試しください!

リストのリストを取り、タプルのリストを返します。

説明

リストの理解を完全に乱用します。これは同等の拡張コードです:

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 -h23 11バイト

4Æ=sUb_dà z

それを試してみてください


説明

                :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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.