删除二维数组的周围零


40

这是该问题的二维版本。

给定一个仅包含非负整数的非空二维数组/矩阵:

[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
对于最后一个测试用例,我们可以给出假输出而不是空矩阵吗?
sundar-恢复莫妮卡

1
另外,如果输出可以是非平方矩阵,请为此添加一个测试用例。
sundar-恢复莫妮卡

1
一个测试用例破坏了我先前提交的内容:([[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]]结果的宽度/高度为1
Conor O'Brien

1
嘿,是否可以添加测试用例
[111112311111]
Beta Decay,

Answers:



39

Wolfram语言(Mathematica),42个字节

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

在线尝试!

细胞自动机实际上是生命宇宙一切的答案。1个

怎么样?

CellularAutomaton接受输入数组和可选的背景值。因此,{#,0}假设背景为0s ,则指定应将元胞自动机规则应用于输入。

整洁的事情是CellularAutomaton裁剪输出,以便不存在背景单元格的边界(因为否则输出位于无限平面上)。

该代码应用了规则{Null, {}, {0, 0}}-将头Null应用于每个像元的0半径邻居(即仅将中心:像元本身)应用于特定0时间。结果是原始输入,但是背景被删除(即裁剪周围的0s)。


1.看到我的答案的字节数了吗?;)


6
不错的内置滥用方法... Mathematica具有内置的,只是不直接暴露。
user202729

3
没有XKCD 505参考?
硕果累累'18

+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的不足,我们定义了一个函数g(),它可以根据全局标志z的值在输入矩阵a []的行或列上进行操作。

g()查找非空行(如果未定义 z)或非空列(如果定义 z 的最小索引 m和最大索引 M,并返回矩阵本身或给定行的相应切片矩阵

总结一下:

  • 我们首先通过使用z undefined 调用矩阵上的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,Arnauld生活在一个完全不同的维度。但是,如果您非常幸运,可以偶尔找到他错过的一个技巧,并发布一个较短的解决方案。在此过程中,您将对JavaScript有了非常深入的了解。
瑞克·希区柯克

4
@RickHitchcock我不太擅长代码模式识别,即使我以前看过它们,我也会经常丢失很多东西。在这个特定的示例中,我专注于g()的可重用性,但是错过了更新mM(-9字节)的方式上的明显优化。我完全同意,代码编程是一种学习很多语言精妙之处的好方法。
Arnauld

7

Haskell62 61字节

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

在线尝试!

foldr(zipWith(:))ee=[]:e一个略短transpose,且snd.span(all(<1))下降零点的领导名单从名单列表。由于transpose随后reverse在2D名单由90等于一个旋转度,代码f.f.f.f是只有4次下降零点和旋转的领导名单




5

Brachylog24 22 20 19字节

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

在线尝试!

将结果矩阵输出为数组数组;如果为空,则输出false。

(感谢@Fatalize建议内联谓词并节省1个字节。)

说明

谓词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答案,只有在您想编写更具可读性的内容时才实现换行的谓词)。
致命的

@Fatalize谢谢,已更新(最终!)。我从未想过内联谓词语法既是定义又是谓词应用程序,这很酷。
sundar-恢复莫妮卡

5

[R 96 100 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,为“外部” 0S中的向量的和TRUE为阳性,任何“内部” 0秒。此函数适用于输入矩阵的行和列总和。

~! 使用R对操作符的解析器处理。

根据@DigEmAll的注释进行了更正,但有些字节从@ J.Doe回击


1
我认为您应该drop=F像我一样添加,否则这2个测试将返回向量而不是行和列:在线尝试!
digEmAll

97字节drop=F。仍然不足一吨!
J.Doe '18 -10-3

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提供了测试用例代码,以及@ J.Doe节省了10个字节!

  • drop=F由于默认的R行为将单行/列矩阵转换为向量,因此我不得不添加参数。

我没有注意到我之前的代码没有使全零情况失败……现在不幸的是,它修复了很多字节:(
digEmAll

1
我希望我可以+2。确实很好地使用Fivenum。
JayCe '18年

79个字节使用range和调整索引
J.Doe '18年

1
@ J.Doe:当然可以!好主意,谢谢!
digEmAll


3

Python 2,71个字节

通过修改输入返回。列表应作为输入传递。

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

在线尝试!


Python 2,77个字节

这也修改了输入,但是有效。

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

在线尝试!





2

外壳,11个字节

!5¡(T0mo↔↓¬

在线尝试!

我觉得可以通过缩短!5¡部分来节省一些字节。

这个怎么运作

!5¡(

5th

mo↔↓¬

映射到输入的当前版本,并:在仅丢弃包含0的最长前缀后,将每个字段反转(通过使用Husk's执行此前缀的删除,该功能是从输入的开头开始裁剪最长连续元素的功能)通过函数运行时得出真实结果的列表,即¬逻辑非)。

T0

转置,将丢失的条目替换为0


2

视网膜,87字节

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

在线尝试!说明:

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

直到至少一行不以零开头...

\[0, 
[

...从每一行中删除前导零。

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

直到至少一行不以零结尾...

, 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

算法

  • 做两次:
    • 查找第一个非零行
    • 分割前几行
    • 相反
    • 查找第一个非零行
    • 分割前几行
    • 相反
    • 转置

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
Arnauld

认为您可以通过返回s节省4个字节,从而确保t可以继续使用。[[]]w[0]
Arnauld

2

Python 2中118个 116字节

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

在线尝试!


已保存:

  • -2个字节,感谢shooqie

1
您可以通过分配s=sumlambda定义来节省两个字节
shooqie

2

PHP(> = 5.4),200 194 186 184个字节

(通过返回null而不是空数组来返回-6个字节)

(感谢Titus提供 -8个字节)

(-2个字节,由于引用了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;}

在线尝试!

怎么样?

查找行($m$M)和列($n$N)的最小和最大索引,并将输入替换为从$m,$n到的子数组$M,$N(这是通过引用进行的调用)。


使用if($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}
Titus

...和两个字节while($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1);
Titus

@Titus:感谢您的出色提示。喜欢使用&&和的技巧,||我敢肯定我也可以在其他地方使用该技巧。
2点

1
您可以通过调用调用来保存另外两个字节:$a=而不是return
泰特斯

2

八度,48 49字节

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

在线尝试!

查找非零点,并在新的稀疏矩阵中重新排列它们。


@alephalpha答案已更新!
rahnema18年


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小号

这个怎么运作:

  • 做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

在线尝试!

说明

这会将矩阵旋转90度数(x=rot90(x))足够次数(for k=1:... end)。旋转数是的倍数4,因此最终矩阵具有原始方向。具体而言,转4数是矩阵(nnz(~x)*4)中零的数目的乘积。

对于每次旋转,如果左侧有一个或多个仅由零组成的列,则将其删除(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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.