Büidans


30

挑战很简单:编写一个程序或函数,当给定一个有限的非负整数时,该程序或函数将输出一个嵌套数组。

规则

  • 您的代码必须为每个 0≤n≤2 31的整数生成唯一的有效嵌套数组。
  • 必须在此范围内输出每个带有最多16个方括号的嵌套数组。(这并不意味着您的代码永远不会输出带有超过16个方括号的嵌套数组。)
  • 您的代码可能会输出嵌套数组的字符串表示形式,而不是实际数组(带或不带逗号)。

一种可能的映射:

0 -> []
1 -> [[]]
2 -> [[[]]]
3 -> [[], []]
4 -> [[[[]]]]
5 -> [[[], []]]
6 -> [[[]], []]
7 -> [[], [[]]]
8 -> [[], [], []]
9 -> [[[[[]]]]]
etc.

计分

这是,因此以字节为单位的最短代码获胜。


有时间/记忆限制吗?
丹尼斯

@Dennis 1小时的时间限制似乎合理吗?我不知道什么是合适的记忆。
ETHproductions 2016年

如果有时间限制,内存并不是什么大问题。一小时似乎很慷慨。我不想等待一个小时来验证我的代码是否足够快。
丹尼斯

4
我希望没有时间限制。这给出了独创性更大的空间
吨Hospel

2
@TonHospel您可以不使用逗号输出。我想没有时间限制就可以了,只要您可以证明您输入的内容有效即可。
ETHproductions 2016年

Answers:


12

Python 2.7版,172个149 124 118字节

x=input();y="";z=0
for b in bin(x)[2+(x<1):]:y+="[]"[b<"1"];z+=b>"0"or-1;z+=99*(z<0)
print"["+(y,"[]"*(x+16))[z>0]+"]"

说明:

定义一个双射[1]0。括号的任何排列都可以写成二进制数,反之亦然,例如[][]1010(10)和[[][]]110100(52)。最多15个开括号(总共30个括号)的所有有效排列都由最多30位(忽略前导零)的数字所覆盖,这些数字恰好是小于2 31的数字。

第一个for循环给出此双射的倒数,将数字转换为括号的排列,同时检查该排列是否有效。

为避免冲突,在打印语句中用长括号替换了无效的安排。例如11(3)↔ [[无效,因此我们将3 + 16括号串联起来。这样可以确保所有安排都是唯一的。

将所得的结构被放置在一对托架,使一个嵌套阵列内,使1010(10)成为[[][]]110100(52)变成[[[][]]]。额外的开放式括号表示我们现在已经用16个开放式括号覆盖了所有阵列。


以下程序可用于找出给定数组的编号,最多包含16个括号。

s=raw_input();o="";
for c in s[1:-1]:
 if c=="[":o+="1"
 if c=="]":o+="0"
print int(o,2)

当操作员指定“唯一”时,对操作员意图的很好滥用
Ton Hospel

那只是天才。做得好。(并且允许使用无逗号格式。)
ETHproductions

12

Python,153 128字节

s=l=0;r="";n=input()
for d in bin(n)[2:]*(n>0):c=d<"1";l=[l,s>1][c];r+="]"*c+(1-l*c)*"[";s+=1-c-l*c
print"["+r+"["*l+"]"*(s+l+1)

通过从左到右查看二进制数,将数字n映射到嵌套列表。该算法适用于任意数量,不仅限于2 32

  1. 如果当前的二进制数字为1,则输出[
  2. 否则,如果到目前为止我们输出的方括号序列将由一个单独的方括号output平衡][
  3. 否则,如果这是二进制数中的最后一个0,则输出][
  4. 否则输出]

最后,我们关闭所有打开的括号。


5

Spoon,63个字节(501位)

000001001001001011001101001010011011111001010001000000101010
101101100110100101101001000101100010001000000100011000010000
000000000000001110111110010000001110110110010100100100100100
000110011010001000000110110000010000001010110011011011011001
000000011010010010010001000000111011011011101001001001000110
110110010100100101011001000100000011010001000000111011011001
010010010010010001101101101001000110110010110001101101101101
100100010001010010001010011011001000000011001101001001010010
000001100101001000111

这是以下转换为汤匙的Brainfuck程序:

-[+[+<]>>+]<+++.[->+>+<<]>>++>>,[>-[<->-----]+<+++[-<+<<.>>>>-<]>[-<<-[->+<]<<<[-]>>>>[-<+<<<+>>>>]<<.>>+<[>-]>[-<+<<.>>>>]<<>>]<,]<<<<[>.>.<<[-]]>>>+[-<.>]+

在stdin上读取二进制整数,并在stdin上输出嵌套列表。要求输入0作为空字符串(无数字),并且需要具有8位单元格的Brainfuck解释器。与我的Python答案相同的算法。

可读版本:

-[+[+<]>>+]<+++.           push open bracket and print it
[->+>+<<]                  dup
>>++                       increment to close bracket

>>,[                       read input loop
    >-[<->-----]+<+++          subtract 48 and set up if/else
    [-                         if c == 1
        <+                         increment s
        <<.>>>                     output open bracket
    >-<]>[-<                   else
        <-[->+<]                   decrement and move s
        <<<[-]                     zero l
        >>>>[-<+<<<+>>>>]          l = s and restore s
        <<.>                       output close bracket
        >+<[>-]>[-                 if s == 0
            <+                         undo s decrement
            <<.                        output open bracket
        >>>>]<<
    >>]<
,]

<<<<[                      if l
    >.>.                   output pair
<<[-]]
>>>+[-<.>]                 output close bracket s+1 times

3
我们最近在另一个答案上进行了讨论,并且似乎没有实际的解释器能够处理63字节的文件。参考实现使用字节0x30和0x31,因此此答案将需要一个501 字节的文件。
丹尼斯


5

Perl,80 79字节

再次使用orlp的算法,但是这次我首先检查它是否有效...

包括+1的 -p

在STDIN上输入号码

nest.pl <<< 8

nest.pl

#!/usr/bin/perl -p
($_=sprintf"%b",$_).=2x(s^.^$&or++$n-pos&&/.0/g?++$n%1:$`&&21^eg-$n);y;102;();

Linus的解决方案是在perl中使用64个字节:

#!/usr/bin/perl -p
$_=sprintf"%b",/.+/g;$_=10x($&&&$&+16)if!/^(1(?1)*0)+$/;y;10;()

Dennis的解决方案是在perl中使用59字节(对于大数,速度越来越慢):

#!/usr/bin/perl -p
1while$_-=(sprintf"%b",$n++)=~/^(1(?1)*0)+$/;$_=$&;y;10;()

我觉得您应该将其计为65个字节(实际上不是64个字节)吗?
莱纳斯(Linus)2016年

1
@Linus虽然您的规避规避是出色的,值得所有批评,但我确实认为这有点作弊。对于计分-p计为1个额外的字节
吨Hospel

5

Python 3中,120个 114字节

def f(n,k=0):
 while~n:
  k+=1
  try:r=eval(bin(k).translate({48:'],',49:'['})[3:-1])+[];n-=1
  except:0
 print(r)

Ideone上进行测试

怎么运行的

定义的函数f接受输入n并将k初始化为0。我们将继续增加k直到N + 1的值ķ在一个有效的输出结果。每次我们找到k的值时,n达到-1时就递减n~n得出0,并打印与k的最后一个值相对应的列表r

从正整数到嵌套列表(即k r)的部分映射必须是双射的,但是没有其他约束。此答案中使用的一个操作如下。

  1. k转换为以0b开头的二进制字符串表示形式。

    例如44↦“ 0b101100”

  2. 全部替换 字符串表示形式中的 0(代码点48)替换为字符串“]”,并将所有1(代码点49)替换为[

    例如,“ 0b101100”↦“],b [],[[],],”

  3. 删除前三个字符(它们对应于“ 0b”)和结尾字符(希望是逗号)。

    例如,“],b [],[[],],”↦“ [],[[],]”

  4. 尝试评估生成的代码。如果这导致错误,则k不会映射到任何列表。

    例如,“ [],[[[],]”↦([],[[]])

  5. 将结果(如果有)与空列表连接起来。如果这导致错误,则k不会映射到任何列表。

    例如,([[],[[]])+ []错误,因为+无法连接列表和元组。


4

Haskell,71个字节

p 1=["[]"]
p n=['[':h++t|k<-[1..n-1],h<-p k,_:t<-p$n-k]
((p=<<[1..])!!)

最后一行的main函数索引所有嵌套数组的列表,并按大小(方括号的数量)排序。因此,所有大小最多为16的数组都将首先列出。

首先让我们看一下更好或更短的代码,但是Haskell的类型检查器拒绝接受。

p 1=[[]]
p n=[h:t|k<-[1..n-1],h<-p k,t<-p$n-k]
((p=<<[1..])!!)

p输入函数n提供了所有嵌套大小数组的列表n(方括号)。这是递归完成的。每个这样的数组都由一些h大小的头(第一个成员)k和一些大小的尾部t(其他成员)组成n-k,两个大小都不为零。或者,它是size的空数组n==1

p=<<[1..]然后将表达式展平p(1), p(2), ...为按大小排序的所有数组的单个无限列表

[ [], [[]], [[],[]], [[[]]], [[],[],[]], [[],[[]]], [[[]],[]], [[[],[]]], ...

和主要功能索引到它。

...或者,如果Haskell不抱怨“构造无限类型:t〜[t]”,那将会是。Haskell不能表示其元素为任意嵌套数组的上面的无限列表。其所有元素必须具有相同的类型,但类型t不能与t的列表相同。其实功能p没有依赖类型,就不能为本身分配一致类型,这是Haskell缺少的。

因此,我们改为使用括号中的字符串,通过作用于[]字符来模拟cons操作。这需要额外的9个字节。使用类型安全语言打高尔夫球的危险。


3

Haskell,87 82字节

0#0=[""]
n#m=['[':x|n>0,x<-(n-1)#m]++[']':x|n<m,x<-n#(m-1)]
(([0..]>>= \y->y#y)!!)

输出数组元素。用法示例:(([0..]>>= \y->y#y)!!) 3-> "[][]"

函数通过跟踪剩余的每个#嵌套数组,将所有嵌套数组构建为左括号nm右括号的字符串。一律以开头n == m。main函数调用y # y每一个,y <- [0,1,...]并在输入给定的索引处选择元素。


2

MATL,31个字节

O`@BEqXJYs0&)0>w~hA+tG>~]x92J-c

在线尝试!验证前几个测试用例(花费几秒钟)。

生成的映射为:

0 -> []
1 -> [[]]
2 -> [[][]]
3 -> [[[]]]
4 -> [[][][]]
5 -> [[][[]]]
6 -> [[[]][]]
7 -> [[[][]]]
...

说明

该代码将继续测试不断增长的二进制数,并0-1;代替数字。也就是说,使用1-1作为数字。数字1将代表'['并且-1将代表']'

程序计数直到获得n +1个有效数字。如果满足以下两个条件,则数字有效:

  1. 数字总和为零(即1和相等-1
  2. 除末尾(在条件1处为零)外,累积的总位数始终为正(也就是说,累积的1位数始终超过的位数-1)。

一旦获得n +1个有效数字,最后一个数字将1变为[-1变为音译],然后显示出来。

码:

O          % Push 0: initial count of valid numbers
`          % Do...while
  @        %   Push iteretation index k, starting at 1
  B        %   Convert to binary. For example, k=6 gives [1 1 0 0]
  Eq       %   Multiply by 2, subtract 1: transforms [1 1 0 0] into [1 1 -1 -1]
  XJ       %   Copy that to clipboard J, without popping it
  Ys       %   Cumulative sum: gives [1 2 1 0]
  0&)      %   Split array into its final element and the rest. Gives 0, [1 2 1]
  0>       %   Yields 1 for positive entries (condition 2). So in this case it
           %   gives [1 1 1]
  w        %   Swap: moves second-top element in the stack (0 in this case) to top
  ~        %   Negate: yields 1 if input is 0 (condition 1). Gives 1 in this case
  h        %   Concatenate horizontally. Gives [1 1 1 1]
  A        %   All: gives 1 if all elements are 1. Gives 1 in this case, meaning
           %   that this k is valid
  +        %   Add the result (0 or 1) to the count of valid numbers
  t        %   Duplicate
  G        %   Push input n
  >~       %   Loop condition: false (exit loop) if count exceeds input n
]          % End loop. At this point the result is in clipboard J, in 1/-1 format
x          % Delete count
92         % Push 92. Will be used to convert 1, -1 to '[', ']' (ASCII 91, 93)
J          % Push result in 1/-1 format
-          % Subtract: converts 1 to 91, -1 to 93
c          % Convert to char. Implicitly display
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.