一个简单的数字系统


19

让我告诉您一个简单的数字系统。(我为此挑战而弥补)

该系统所包含的功能()[]{},和<>

1。 ()

如果()未提供任何参数,则结果为0

()给定一个或多个参数时,它将求和为参数的总和。

2。 []

如果[]未提供任何参数,则结果为-1

[]给定一个或多个参数时,它将得出第一个参数减去其他参数的总和。

3。 {}

如果{}未提供任何参数,则结果为1

{}给定一个或多个参数时,它将求值为这些参数的乘积。

4。 <>

如果<>未提供任何参数,则结果为1

<>给定一个或多个参数时,它将求出第一个参数整数除以其他参数的乘积。

你的任务

在这个简单的数字系统中,给定一个包含有效数字的字符串(这意味着括号是平衡的,不能除以0等),请打印其值。

测试用例

() -> 0
(()()) -> 0
([][]) -> -2
({}<>) -> 2
({}[]) -> 0
[] -> -1
[[][]] -> 0
[()<>] -> -1
{()} -> 0
{([]<>)} -> 0

请记住,这是,所以字节最少的代码将获胜。


13
我对此有一个很好的名字,我完全是虚构的,没有从其他任何地方得到:片状的!
ETHproductions 2016年

4
@ETHproductions no
Oliver Ni


2
除法是浮点除法还是整数除法?
xnor

1
@Oliver当一个或两个操作数为负数时,整数除法应如何工作?什么是4个预期结果5/35/-3-5/3-5/-3
马丁·恩德

Answers:


2

Dyalog APL,94 字节

o←{(⊂(1⊃⍵),⍺⍺⊃⍵),2↓⍵}⋄u←{(⊃⍵,⍺⍺1)⍺⍺⍵⍵/1↓⍵}⋄⍎⍕'+/o' '-u+o' '×/o' '÷u×o' '(⊂⍬),'[')]}>'⍳⌽⍞],'⊂⍬'

用途 ⎕IO←0

内容替换)]}>与一个函数调用,需要一个栈,其顶部框架上施加操作,删除它,并且将结果附加到它的下一个帧(一元运算符o是用于该;二元操作者u把手的更复杂的情况-÷

替换([{<为向框架添加框架的代码((⊂⍬),

用一个空框架(⊂⍬)的初始堆栈执行结果表达式(取反,以匹配APL的执行顺序)


5

Haskell中,357 306 277 251 228 224 188 185 180字节

具有显式堆栈的基于令牌的解析器。(%)接受一个令牌堆栈和一个字符,然后为推送(opcode,defaultnumber)或(0,number)({[<,或者弹出最上面的数字和一个opcode并为推送答案)}]>。操作码由ascii枚举黑客编码。

感谢@ChristianSievers的出色回答,我从中借鉴了一些想法。

一线!

s%c|elem c"([<{",g<-div(fromEnum c)25=(g,[0,0,1,-1,1]!!g):s|(a,(o,n):b)<-span((==0).fst)s=(0,[foldr1(flip$[(+),quot,(-),(*)]!!(o-1))$snd<$>a,n]!!(0^length a)):b
snd.head.foldl(%)[]

现在减少了错误处理!用法:

*Main> map (snd.head.foldl(%)[]) ["()","(()())","([][])","({}<>)","({}[])","[]","[[][]]","[()<>]","{()}","{([]<>)}"]
[0,0,-2,2,0,-1,0,-1,0,0]

感谢@ChristianSievers保存14 + 3字节!

感谢@Zgarb节省了+4个字节!


1
如何(0,[0,0,1,-1,1]!!o):s在第五行?
Christian Sievers,2016年

@ChristianSievers当然!
昂斯,2016年

切换的定义!,因此您可以(s:_)!_=d s作为第二种情况。另外,我认为您可以x<-p$d<$>init a,y<-d$last a在的最后一种情况下进行绑定%
Zgarb

@Zgarb谢谢!我找到了一种进一步统一评估的方法。
昂斯,2016年

1
在第三行,%您可以在_:b和周围放置括号g c
Zgarb

3

Python 2中,292 265 248 235 223 206 204字节

r=reduce
s=input()
for n in')]}>':s=s.replace(n,'),')
for a in'(*x:sum(x)','[a=-1,*x:a-sum(x)','{*x:r(int.__mul__,x,1)','<a=1,*x:r(int.__div__,x,a)':s=s.replace(a[0],'(lambda %s)('%a[1:])
print eval(s)[0]

用执行括号操作的lambda替换所有括号,然后评估结果Python代码。需要其输入加上引号,例如'[<><>([]{})]'

该程序将方括号的类型存储为中每个字符串的第一个字符for,并将关键字之后的所有内容存储lambda为其余字符。然后,它使用第一个字符进行替换;其余部分合并成lambda(lambda*x:sum(x))()

在Ideone上尝试!


3

PEG.js(ES6),132字节

x=a:[([{<]b:x*[)\]}>]{var x='([<'.indexOf(a)
b.length^1||b.push(0)
return~~eval(b.length?b.join(('+-/'[x]||'*')+' '):~-('10'[x]||2))}

现在应该修复。

说明

更具可读性:

x=a:[([{<]
  b:x*
  [)\]}>]
{
  var x='([<'.indexOf(a)
  b.length^1||b.push(0)
  return ~~eval(
    b.length?
      b.join(('+-/'[x]||'*')+' ')
    :~-('10'[x]||2))
  )
}

PEG.js是专门用于解析的Javascript的扩展版本。非常严格,这就是为什么我必须使用var。另外,在字符串中似乎有一个带括号的bug,这使代码大大膨胀。

首先,我们定义一个规则x,该规则匹配任何a包含或不包含包含与该规则匹配的多个表达式的方括号x

对于每一个匹配规则x,我们推0到内匹配的数组b如果b长度为1,。

如果b的长度> 0,则我们找到ain 的索引([<+-/使用该索引获取字符。如果结果未定义(表示a{),则将结果转换为*。最后,我们在空间上加入b加上结果。

如果blength = 0,则我们找到ain 的索引([<10使用该索引获取字符。如果结果未定义(表示原a{<),则将结果变为2。最后,我们简单地递减。

最后,我们只需要评估表达式并取整结果即可。


3

Perl,113 + 2 = 115字节

运行-lp(2个字节的罚款)。

/\W/,eval"sub $`\{\$#_?(shift)$&&$'1}"for qw'a+a:1- b-a:- c*c: d/c:';y/([{</a-d/;s/\W/0),/g;s/\pL\K/(/g;$_=eval

更具可读性(请注意:此“更具可读性的版本”实际上不会运行,因为我将注释放在语法上不允许的地方):

              # -p option: read a line of input into $_ at program start
              # -l option: remove the final newline whenever reading
do {          # for each element of a list, given later:
  /\W/;       # place an initial identifier in $`, the next character in
              # $&, and the rest of the element in $'
  eval qq{    # then evaluate the following template, with substitutions:
    sub $` {  # define a subroutine named $`, that does this:
      \$#_ ?  # if there is more than one argument                   
      (shift) # then return the first argument $&-ed with
      $& &$'  # the result of a recursive call with the tail of the arguments
              # else (the "else" is a colon taken from $', not the template)
      1       # return (the remainder of $' applied to) 1
    }
  }
} for qw'     # specify the list by splitting the following on whitespace:        
  a+a:1-      # a(head,tail) = len(tail>1) ? head+a(tail) : 1-1
  b-a:-       # b(head,tail) = len(tail>1) ? head-a(tail) : -1
  c*c:        # c(head,tail) = len(tail>1) ? head*c(tail) : 1
  d/c:        # d(head,tail) = len(tail>1) ? head/c(tail) : 1
';
y/([{</a-d/;  # replace ( [ { < with a b c d in $_
s/\W/0),/g;   # replace whitespace, punctuation in $_ with the string "0),"
s/\pL\K/(/g;  # place a ( after (\K) each letter (\pL) in $_
$_=eval       # evaluate $_ as a Perl program, storing the result back in $_
              # -p option: print $_ to the user at program end
              # -l option: output a newline whenever printing

基本思想是我们通过文本处理将输入转换[()<>]为Perl程序b(a(0),d(0),0),。Perl可以使用逗号结尾。此前,我们定义的函数abcd有一样的效果()[]{}<>从我们正在实施的语言结构; 它们每个都忽略最后一个参数(末尾为0),该参数被包括在内以确保所有输入均正确解析,并使用在函数式编程中常见的实现方式工作,其中头部和尾部被分别处理。因为b(e,f,g,0)means e-f-g,即特别对待其第一个参数,而a对称地对待其参数(a(e,f,g,0)手段递归和e+f+g),我们实现ab通过致电acd有类似的关系。所有这四个函数都非常相似,因此我们在运行时生成它们,而不是分别实现。我们将适用于所有四个函数的模板存储在字符串中,然后通过将字符替换为模板来生成函数。

因为Perl进行/浮点除法,所以实现{}也是如此。我假设这本身不是问题,或者-Minteger(选择所有算术运算都是整数运算的语言变体)是免费的,因为否则我将不得不花费额外的字节在Perl中编写整数除法,这似乎根本不是问题所在。(我认为您必须将四个字节更改(shift)int+(shift);我尚未对此进行测试。)


2

八度,215个 206 198字节

S='sum(x(:))-sum(x(2:end))';Y='(@(x)isempty(x)';c=']) ';[~,~,u]=unique(['()<>[]{}',input('')]);eval([{'sum([',c,[Y,'+fix((',S,')/prod(x(2:end))))(['],c,[Y,'*-1+',S,'*2)(['],c,'prod([',c}{u(9:end)}])

在线尝试


2

PHP,315个 300 285 258 250 244字节

for($s=$argv[1];$r=!$r;)foreach(["(+)1","[-]0","{*}2","</>2]as$p)if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m)){if(""==$v=strtok($m[1],_))$v=$p[3]-1;while(""<$n=strtok(_))eval("\$v$p[1]=$n;");$s=strtr($s,[$m[$r=0]=>_.$v]);}echo substr($s,1);

用下划线+值替换子表达式;迭代不做替换时循环中断。

自从初次接触C以来已有19年,而使用PHP已有17年;
这是第一次strtok有意义,有助于节省24个字节!

分解

for($s=$argv[1];    // take input from argument
    $r=!$r;)        // toggle $r; loop until no replacement has taken place
    foreach(["(+)1","[-]0","{*}2","</>2]as$p) // loop through operations
        if(preg_match("#$e$p[0]([-_\d]*)$e$p[2]#",$s,$m))   // find a match
        {
            if(""==$v=strtok($m[1],_))  // init $v with first token from sub-match
                $v=$p[3]-1;             // if no token, init with default value
            while(""<$n=strtok(_))      // loop through tokens
                eval("\$v$p[1]=$n;");       // operate
            $s=strtr($s,[$m[$r=0]=>_.$v]);  // reset $r; replace match with underscore+value
        }
echo substr($s,1);  // print result

@Oliver没有在这里殴打任何人;但是谢谢你的乐趣!
泰特斯(Titus)

2

ES6(JavaScript), 250171154149,147字节

纯Javascript版本。

“元编程”(如此处的其他大多数答案一样),通过对输入文本进行大量直接文本替换(即保持程序结构不变),将输入程序文本转换为相应的Javascript程序。

可以进一步打高尔夫球。

更新(v2.1)

  • 减去两个字节(在三进制表达式中删除了括号)
  • 通过使用变量进行结果提取,消除多余的5个字节,从而摆脱了多余的“ []”

更新(v2)

刚刚意识到ES数组中的待处理逗号完全有效,因此可以删除整个逗号标准化代码。@Titus还提供了关于优化字母查找的出色建议。

更新(v1)

删除重复的“替换”别名。

更新(v1)

  • 使用更好的字母:()=> 1+ [] => 0 {} => 2 * <> => 2 /(每个char可直接用作值或运算符)

  • 用replace()替换了reduce()(字母映射)

  • 将恒定的内联,打开和关闭括号处理合并为一个步骤

打高尔夫球(v2.1)

s=>eval("o="+s.replace(/./g,r=>"2+1-3*3/"["()[]{}<>".indexOf(r)]).replace(/\d\D?|\D/g,r=>r[1]?r[0]-2+",":r*1?'([':`].reduce((r,a)=>r${r}a)),`)+"o

打高尔夫球(v1)

(s,A="(2)+[1]-{3}*<3>/")=>eval(s[R="replace"](/./g,r=>A[A.indexOf(r)+1])[R](/\d\D?|\D/g,r=>r[1]?r[0]-2+",":(r[0]*1?'([':`].reduce((r,a)=>r${r}a)),`))[R](/,(\])|,$/g,"$1"))    

打高尔夫球(v0)

([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

解释(v0)

//BEGIN 

//s - input text, A - alphabet, R - "String.replace()" alias
E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(

//Replace input alphabet by a more friendly one, to avoid too much escaping and quoting
// () - ab, [] -cd, {} - ef, <> - gh
s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')

//Replace no-arg invocations with a corresponding constant value
// () => 0, [] => -1, {} => 1, <> => 1      
[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')

//Replace opening brackets with "(["
[R](/[aceg]/g,"([")

//Replace closing brackets with "].reduce(...)),"
//An arithmetic operation to apply (+-*/) is chosen based on the bracket type 
//and is substituted into the template 
[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)

//Strip excessive commas
[R](/,(\])|,$/g,"$1")
);

//END: eval() the result


Example:
E("{([]<>()<>{})(<><>)}")
=> eval("([([-1,1,0,1,1].reduce((r,a)=>r+a)),([1,1].reduce((r,a)=>r+a))].reduce((r,a)=>r*a))")
=> 4

测试

E=([...s],A="(a)b[c]d{e}f<g>h",R="replace")=>eval(s.reduce((r,c)=>r+=A[A.indexOf(c)+1],'')[R](/ab|cd|ef|gh/g,r=>({d:-1,b:'0'}[r[1]]||1) + ',')[R](/[aceg]/g,"([")[R](/[bdfh]/g,r=>`].reduce((r,a)=>r${"+*-/"["bfdh".indexOf(r)]}a)),`)[R](/,(\])|,$/g,"$1"))

T=(s,a)=>{
    console.log(s,r=E(s),r==a?"OK":"NOT OK");
}

T("()",0)
T("(()())",0) 
T("([][])",-2)
T("({}<>)",2) 
T("({}[])",0) 
T("[]",-1)
T("[[][]]",0) 
T("[()<>]",-1) 
T("{()}",0) 
T("{([]<>)}",0)

测试输出

() 0 OK
(()()) 0 OK
([][]) -2 OK
({}<>) 2 OK
({}[]) 0 OK
[] -1 OK
[[][]] 0 OK
[()<>] -1 OK
{()} 0 OK
{([]<>)} 0 OK

1
您的v0版本可以附带s.reduce((r,c)=>r+="abcdefgh"["()[]{}<>".indexOf(c)],'')(-5)吗?如果是这样,您可以记住indexOf一个变量,并从第三个字符串文字中获取运算符。
泰特斯

2

Haskell,184 179 172 161 160 159 151 148 145字节

s%(c:i)|elem c")}]>"=([1?(*),sum,1?quot,(-1)?(-)]!!mod(fromEnum c)5$s,i)|(r,j)<-[]%i=(s++[r])%j
[v]%e=(v,e)
(v?_)[]=v
(_?o)s=foldl1 o s
fst.([]%)

递归下降,因为Haskell而使输入线程化。像往常一样,最后一行不是定义,而是说明解决问题的功能。因此,要进行测试,请将除最后一行以外的行放入文件中,加载并执行以下操作:

*Main> fst.([]%) $ "{([][][])([][])}"
6

感谢@Zgarb的启发和很多详细的提示,感谢@Angs从他的解决方案和进一步的提示中得到的启发。

没有指定除法应该如何处理负整数。无论如何,重复使用div似乎是错误的,因为div与将剩余值的乘积使用一次不同。现在用quot,我得到了相同的结果<{}([][])[]><{}{([][])[]}>

有关不错的,几乎可读的代码,请查看第一个版本。中间版本包含各种漂亮而令人生畏的代码,有助于理解此版本。


我认为您可以通过定义(!)=(,)和使用!而不是显式元组来节省几个字节。
Zgarb '16

如果你定义m xd x1#x0#x,可以合并的情况下,m[x]d[x]成一个,我认为可以节省一些字节太多。
Zgarb '16

@Zgarb谢谢!我差点错过了最后一对,没有那对,那!把戏就不会付诸东流。您的第二个建议是邪恶的,这里有我几乎可读的代码……聪明!
Christian Sievers,2016年

呵呵,我才意识到 s%(c:i)=(s?c,i) and s?')'=sum s等会短很多,因为您可以摆脱重复的is。..不用等待,由于这种s%(_:i)情况,这可能行不通。
Zgarb '16

1
失去了反引号的elemdiv,应该节省一些更多的字节。
Zgarb '16

1

JavaScript(ES6),否eval,156个字节

f=s=>s==(s=s.replace(/(.) ?([- \d]*)[\]})>]/,(_,c,s)=>` `+(s?s.split` `.reduce((l,r)=>c<`<`?l- -r:c<`[`?l/r|0:c<`{`?l-r:l*r):c==`[`?-1:c==`(`?0:1)))?+s:f(s)

说明:regexp查找第一个未处理的右括号,并匹配(大概)对应的右括号和之间的任何参数。根据运算符对参数进行拆分和缩减(可悲的是'('和'['不是+and 的最佳对-),或者如果没有参数,则计算出适当的值(同样,字符与值的匹配不是最佳的)从我的角度来看),然后将结果替换为前导空格,以将其与其他结果分开,然后该函数递归调用自身,直到不再需要进行任何更改为止,在这种情况下,它将返回结果值。例:

[()<>]
[ 0<>]
[ 0 1]
 -1

f(“([[] [])”) => 0(而不是2)
zeppelin

其他一些测试对我来说也是失败的(您可以尝试在答案中给出测试代码),可能是由于:f(“ []”)=> 0,因为“ []”是每个失败测试的一部分。
Zeppelin

@zeppelin糟糕,这是由于打高尔夫球不好造成的。我已还原到以前的版本,但可悲的是,这花了我几个字节。
尼尔,
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.