挑战数组2:分离嵌套数组


36

注意:这是一系列挑战中的第二个问题。对于上一个挑战,请单击此处

分隔嵌套列表

要在嵌套列表中分离值,请对其进行展平,然后包装每个值,使其与以前的嵌套深度相同。

也就是说,此列表:

[1, [2, 3], [4, 4, [5, 2], 1]]

会成为:

[1, [2], [3], [4], [4], [[5]], [[2]], [1]]

挑战

您的任务是编写一个程序,该程序将使用任何嵌套的正整数列表(在您的语言范围内)并执行此分离操作。

您可以提交将列表作为参数的函数,或者执行I / O的完整程序。

因为这是,所以最短的提交(以字节为单位)获胜!*

*禁止使用标准的高尔夫球漏洞。你知道该怎么做。


测试用例

输入列表将仅包含您语言的标准整数大小的整数。为避免语言的限制阻止它们竞争,值的嵌套深度不得超过10。

您可以假定输入将没有空的子列表:例如- [[5, []]]将不给出。但是,主列表可能为空。

[]            ->  []

[[1, 2]]      ->  [[1], [2]]
[3, [4, 5]]   ->  [3, [4], [5]]
[3, [3, [3]]] ->  [3, [3], [[3]]]
[[6, [[7]]]]  ->  [[6], [[[7]]]]
[[5, 10], 11] ->  [[5], [10], 11]

如果我错过了一个极端案例,请不要犹豫发表评论。

我以一个快速的(解开的)Python 3解决方案为例,您可以在repl.it上对其进行测试


添加一个大于单个数字的测试用例,以基于字符串的答案。
orlp

@orlp好主意。
FlipTack

2
我们可以假定一定的最大深度吗?说16岁?
orlp

@orlp我要说的是,最大嵌套深度为10,因为我对您的算法和方法执行比对语言的约束更感兴趣。现在将更新线程。
FlipTack

我可以输出为字符串吗?
Rohan Jhunjhunwala

Answers:


4

Brachylog,16个字节

:{##:0&:ga|g}ac|

在线尝试!

说明

Example input: [1:[2:3]]

:{          }a     Apply the predicate below to each element of the list: [[1]:[[2]:[3]]]
              c    Concatenate: Output = [1:[2]:[3]]
               |   Or: Input = Output = []

  ##                 Input is a list: e.g. Input = [2:3]
    :0&              Call recursively the main predicate with this input: [2:3]
       :ga           Group each element in a list: Output = [[2]:[3]]
          |          Or (not a list): e.g. Input = 1
           g         Group into a list: Output = [1]

Z论点对TIO有何作用?没有它,这似乎会输出true / false,这似乎Z在字节计数中似乎是必需的。
FlipTack

@FlipTack Z告诉Brachylog输出参数是一个变量。这是与结果输出统一的变量。当您删除它时,它会告诉Brachylog输出是一个匿名变量,而是打印主谓词是成功还是失败。这与Prolog中的结果相同,在Prolog中,结果是“放入”变量。
致命

好吧:)不错的答案!
FlipTack

19

Mathematica,24个 21字节

##&@@List/@#0/@#&/@#&

或以下之一:

##&@@List/@#&/@#0/@#&
##&@@List@*#0/@#&/@#&
##&@@List/@#&@*#0/@#&

说明

之所以这么短,是因为它基本上是递归,不需要显式的基本情况。

这里有很多语法糖,所以让我们首先取消它。&表示左侧的未命名函数,其参数写为#。该函数内部#0指的是函数本身,它允许编写未命名的递归函数。但是让我们开始给内部函数起一个名字,然后将其拔出:

f[x_] := ##& @@ List /@ f /@ x
f /@ # &

另一个重要的语法糖是f/@x它的简称,Map[f, x]即它调用f的每个元素xf[x_] := ... f /@ x不会导致无限递归的原因是,在原子上映射某些对象会使原子保持不变,而无需实际调用该函数。因此,我们不需要显式检查基本情况(当前元素是整数)。

因此,该函数f首先递归到内部的最深列表x,此时该列表f/@变为无操作。然后,我们将其称为use ##& @@ List /@。映射List列表只是将每个元素包装在单独的列表中,因此{1, 2, 3}成为{{1}, {2}, {3}}。然后应用 ##&到它,这意味着头部(即外部列表)被替换##&,因此变成##&[{1}, {2}, {3}]。但是##&只需将其参数返回为Sequence(您可以将其视为未包装的列表,或者使用其他语言的“ splat”运算符)。

因此,##& @@ List /@将一个清单{1, 2, 3}变成{1}, {2}, {3}(实际上,最后一件事实际上包裹在头部中Sequence,但是只要我们在任何地方使用该值,该清单就消失了)。

这就留下了一个问题,为什么f它本身还不能解决挑战。问题在于,最外面的列表应该区别对待。如果我们有输入,{{1, 2}, {3, 4}}我们就会想要{{1}, {2}, {3}, {4}}不是 {{1}}, {{2}}, {{3}}, {{4}}。我最初的解决方案通过将最终结果作为参数列表传递来解决此问题,该参数列表Join将还原列表的外部层,但此方法只是通过在输出的映射中使用f 自身来跳过外部层。因此f,仅应用于最外层列表的各个元素,而永远不会触及该列表。

至于其他三个解决方案,第一个解决方案只是简单地应用了递归,在其他情况下f也是如此。其他两种解决方案Map通过首先组合两个函数,然后仅将结果映射一次来避免重复操作。


8

J19 18字节

(<@]/@,~>)S:0 1{::

这是一个匿名动词,它接收并返回装箱的数组,这些数组是J的(相当麻烦的)嵌套数组版本。 看到它通过所有测试用例。

说明

这使用了有点奇怪的操作{::map)和S:spread),它们对盒装数组进行操作。 {::将每个叶子替换为该叶子的装箱路径。 S:将给定的动词应用于给定的嵌套深度,然后将结果喷射到数组中。

(<@]/@,~>)S:0 1{::  Input is y.
(        )          Let's look at this verb first.
        >           Open the right argument,
      ,~            append the left argument to it,
    /               then reduce by
 <@]                boxing. This puts the left argument into as many nested boxes
                    as the right argument is long.
                    This verb is applied to y
               {::  and its map
            0 1     at levels 0 and 1.
                    This means that each leaf of y is paired with its path,
                    whose length happens to be the nesting depth of y,
                    and the auxiliary verb is applied to them.
          S:        The results are spread into an array.

3

R,199字节

function(l){y=unlist(l);f=function(x,d=0){lapply(x,function(y){if(class(y)=='list'){f(y,d=d+1)}else{d}})};d=unlist(f(l));lapply(1:length(d),function(w){q=y[w];if(d[w]){for(i in 1:d[w])q=list(q)};q})}

这个问题很困难。R的列表有点怪异,绝对不可能直接遍历子列表的所有元素。然后确定该列表的深度也不是一件容易的事。然后,挑战就在于重新创建所有元素分离的列表,因此我们还需要一种方法来自适应地创建一定深度的列表。

该解决方案包括两个主要部分。一个遍历所有列表并记录深度的递归函数:

  f=function(x,d=0){
    lapply(x,function(y){
      if(class(y)=='list'){
        f(y,d=d+1)
      } else {
        d
      }})
  }

unlist(l)存储了存储在中的vector的每个条目的深度时d,我们通过隐式创建一个列表lapply,并使用以下函数填充它:

  lapply(1:length(d),function(w){
    q=y[w]
    if(d[w]){
      for(i in 1:d[w]){
        q=list(q)
      }
    }
    q
  })

在此apply调用中,我们q使用列表中条目的值创建一个对象,检查其深度并查看其是否为非零。如果为零,我们可以将其保留为数字值。如果它不为零,则需要将其嵌套在一定数量的列表中。因此,我们将for称为循环d时间,然后重复调用q=list(q)

lapply然后将所有这些值q放在列表中,以创建所需的输出。

以适当的间距完成程序,例如:

function(our.list){
  values <- unlist(our.list)
  f <- function(part.list, depth = 0){
    lapply(part.list, function(y){
      if(class(y)=='list'){
        f(y, depth <- depth + 1)
      } else {
        return(depth)
      }})
  }
  depths <- unlist(f(our.list))
  new.list <- lapply(1:length(depths), function(w){
    q <- values[w]
    if(depths[w] != 0){
      for(i in 1:depths[w]){
        q <- list(q)
      }
    }
    return(q)
  })
  return(new.list)
}

不错,这是我在测试用例的最初Python解决方案中使用的方法:)
FlipTack 16/12/21

is.list(y)代替class(y)=='list'?无法验证这是否确实有效。
朱塞佩



2

C(gcc),147个字节

d=0,l,i;
P(n,c){for(;n--;)putchar(c);}
main(c){for(;~(c=getchar());l=i)i=isdigit(c),P((l<i)*d,91),P(i,c),P((l>i)*d,93),P(l>i,32),d+=(92-c)*(c>90);}

输入示例:

1 [23 3] [40 4 [5 2] 1]

输出示例:

1 [23] [3] [40] [4] [[5]] [[2]] [1]

2

堆积,非竞争,25字节

{e d:e$wrap d 1-*}cellmap

此函数的作用是修改堆栈的顶部成员。如果您要使用真正的功能,只需在开始和结束处添加[]在这里尝试!

这是可读的版本:

{ arr :
  arr { ele depth :
    ele   $wrap depth 1- * (* execute wrap n times, according to the depth *)
  } cellmap (* apply to each cell, then collect the results in an array *)
} @:a2
(1 (2 3) (4 4 (5 2) 1)) a2 out

测试用例:

(1 (2 3) (4 4 (5 2) 1))    (* arg on TOS *)
{e d:e$wrap d 1-*}cellmap
out                        (* display TOS *)

输出不带换行符:

(1 (2) (3) (4) (4) ((5)) ((2)) (1))

*像参数代码块?
Downgoat

在这种情况下,@Downgoat会包装参数d-1时间。$func是可以操纵的功能。
科纳·奥布莱恩

2

PHP,101 94字节

由于@Christoph节省了1个字节,因此又节省了6个字节。

function s($a){foreach($a as$b)if($b[0])foreach(s($b)as$c)$r[]=[$c];else$r[]=$b;return$r?:[];}

递归函数,非常简单

分解

function s($a)
{
    foreach($a as$b)                // loop through array
        if($b[0])                       // if element is array
            foreach(s($b)as$c)$r[]=[$c];    // append separated elements to result
        else$r[]=$b;                    // else append element to result
    return$r?:[];                   // return result, empty array for empty input
}

结果在哪里初始化?
尼尔,

@Neil:PHP不需要显式初始化。无论$r得到的元件在环或函数返回一个空数组。它可能会产生通知,但是这些通知不会使用默认配置打印。
泰特斯

这不是意味着您只能调用一次吗?
尼尔,

1
您也可能会发疯:!cos()cos()返回null每个数组,每个正整数返回一个float!= 0。我的意思是……谁在乎警告?
克里斯多夫(Christoph)

1
@Christoph:打印警告,不显示通知(在默认配置中)。但这是个好主意!开is_int:逆转条件不会节省任何费用;我需要在else和之间加一个空格foreach。但是:$b[0]整数是NULL
泰特斯

2

Python 2中,122个 106字节

分数非常糟糕,只是一个简单的实现。

感谢@Zachary T帮助节省了16个字节!

def x(l,a=[],d=0):
 n=lambda b:b and[n(b-1)]or l
 if'['in`l`:[x(e,a,d+1)for e in l];return a
 else:a+=n(d)

调用x一个参数即可运行。由于某种原因,它只能运行一次。


您可以更改a+=[n(l,d)]a+=n(l,d),(请注意结尾的逗号)
FlipTack

您甚至需要分配给t
扎卡里

当您多次调用它时,此功能有效吗?
扎卡里

您可以移至n该函数并删除第一个参数,因为它始终是l
扎卡里


2

JavaScript(Firefox 30-57),53个字节

f=a=>[for(e of a)for(d of e.map?f(e):[e])e.map?[d]:d]

到目前为止,我最好的ES6答案是76个字节:

f=(a,r=[],d=0)=>a.map(e=>e.map?f(e,r,d+1):r.push((n=d=>d?[n(d-1)]:e)(d)))&&r

2
在两个代码块中,我认为您都省略了开头f=
科纳·奥布莱恩

@ ConorO'Brien再一次……
尼尔


1

Perl 6的60个 47字节

sub f{[$_~~List??|([$_] for .&f)!!$_ for |$^a]}

在线尝试。

说明:

  1. [... for |$^a]:遍历输入数组,并从中构造一个新数组。
  2. $_ ~~ List ?? ... !! ...:对于每个元素,检查其本身是否为数组。
  3. |([$_] for .&f):如果元素是数组,则对它进行递归应用,迭代从该递归调用返回的新数组的元素,将每个元素包装在自己的数组中,然后滑入外部列表。
  4. $_:如果元素不是数组,则按原样传递它。

1

Haskell,71个字节

data L=N Int|C[L] 
d#C l=((C .pure.d)#)=<<l
d#n=[d n]
f(C l)=C$(id#)=<<l

同样,我必须定义自己的列表类型,因为Haskell的本地列表不能被任意嵌套。L可以从函数返回此新类型,但默认情况下不会打印该新类型,因此为了查看结果,我showL以下对象定义了一个实例:

instance Show L where
  show (N n)=show n
  show (C l)=show l

现在我们可以在REPL中进行一些测试:

*Main> f $ C[N 1, C[N 2, N 3], C[N 4, N 4, C[N 5, N 2], N 1]]
[1,[2],[3],[4],[4],[[5]],[[2]],[1]]

*Main> f $ C[C[N 6, C[C[N 7]]]]
[[6],[[[7]]]]

工作原理:一个简单的递归,它将嵌套级别作为C构造函数传递。我们从标识函数开始,id每当有一个列表(-> pattern match d#C l=)时,我们就对列表的所有元素进行递归调用,再加上一层C(-> C .pure.d#。如果遇到数字,我们只需将nesting-level-function d应用于该数字。


0

APL(Dyalog),44字节*

匿名默认前缀功能。将嵌套的APL列表作为参数,并返回嵌套的APL数组。

∊{⊃⊂⍣⍵,⍺}¨{⊃¨(j∊⎕D)⊆+\-'[]'∘.=j←⎕JSON⍵}

在线尝试!

{} 应用以下显式函数,其中参数由表示

⎕JSON⍵ 将参数转换为JSON

j← 存放在 j

'[]'∘.= 该表j等于左括号(上排)和右括号(下排)

-⌿ 顶行减去底行(垂直差减少)

+\ 累积总和(给出每个字符的嵌套级别)

()⊆ 分区,每当1之前没有1 in时就开始一个新分区…

  j∊⎕D 其中的每一个字符j是该组的成员d igits

⊃¨ 选择每个的第一个(这将为每个多位数的数字提供嵌套级别)

∊{ 将以下列出的函数应用于每个嵌套级别(),并将ϵ列出(展平)参数中的相应元素用作左参数():

,⍺ 散布(列出)数字(因为不能包含标量)

⊂⍣⍵ 封闭时间

 披露(因为最里面的列表本身就是一个附件)


*使用Dyalog经典与⎕ML←3(在许多系统默认),取代io!

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.