评估Dotty字符串


25

编写一个程序,接收仅包含字符.和的奇数长度的字符串:。借助最初为空的堆栈,从该字符串生成一个数字,如下所示:

对于字符串中的每个字符c(从左到右)...

  • 如果c.并且堆栈中的元素少于2个,则将1推入堆栈。
  • 如果c.并且堆栈中有2个或更多元素,请从堆栈中弹出两个顶部值,并将它们的和推入堆栈中。
  • 如果c:并且堆栈中的元素少于2个,则将2推入堆栈。
  • 如果c:且堆栈具有2个或多个元素,请从堆栈中弹出两个顶部值,然后将其乘积推入堆栈。

结果数字是堆栈顶部的值。您的程序应将此编号打印到标准输出(带有可选的尾随换行符)。

(少量分析表明,除非字符串的长度为偶数,否则将仅剩一个数字,这就是我们忽略这些数字的原因。实际上,堆栈中最多不会包含2个元素。)

例如,数字为::...:.:.9:

  2   1   2   2    /______ stack just after the character below is handled
2 2 4 4 5 5 7 7 9  \
: : . . . : . : .  <-- string, one character at a time

为了进行完整性检查,以下是所有长度为1、3和5的字符串的数字:

. 1
: 2
... 2
..: 1
.:. 3
.:: 2
:.. 3
:.: 2
::. 4
::: 4
..... 3
....: 2
...:. 4
...:: 4
..:.. 2
..:.: 1
..::. 3
..::: 2
.:... 4
.:..: 3
.:.:. 5
.:.:: 6
.::.. 3
.::.: 2
.:::. 4
.:::: 4
:.... 4
:...: 3
:..:. 5
:..:: 6
:.:.. 3
:.:.: 2
:.::. 4
:.::: 4
::... 5
::..: 4
::.:. 6
::.:: 8
:::.. 5
:::.: 4
::::. 6
::::: 8

以字节为单位的最短程序获胜。Tiebreaker是较早的帖子。

  • 您可以假设输入始终有效,即,仅包含.:长度为奇数的字符串。
  • 除了编写程序外,您还可以编写一个函数,该函数接受有效的字符串并打印或返回生成的数字。

5
最好的极简均衡器。
dberm22 2015年

Answers:


13

CJam,27 24 23 22字节

q{i]_,+~3<-"1+2* "=~}/

非常简单。我使用CJam的堆栈作为问题中提到的堆栈;)

算法

首先让我们来看看为ASCII码.:

'.i ':ied

[46 58]

由于在CJam中,索引会回绕,让我们看看是否可以直接使用这些值来获得所需的操作。

'.i4% ':i4%ed

[2 2]

因此,我不能简单地在4个长度的操作字符串中使用ASCII码。让我们尝试其他一些值

'.i 10% ':i 10%ed

[6 8]

在长度为4的字符串上归结为

[2 0]

我可以使用此mod 10操作,但这将花费2个字节。让我们尝试其他

'.i5% ':i5%ed

[1 3]

太好了!现在,我们只需为堆栈大小条件减去1即可获得索引,0, 1, 2 and 3并使用5长度数组("1+2* ")作为切换条件。最后一个空格只是一个使长度为5的填充符。与修改操作相比,这仅是一个额外的字节。

q{                  }/    e# parse each input character in this loop
  i]                      e# convert '. or ': into ASCII code and wrap everything
                          e# in stack in an array
    _,+                   e# Copy the stack array, take its length and add the length to
                          e# the stack array 
       ~3<                e# unwrap the stack array and check if stack size is less than 3
                          e# 3 because either . or : is also on stack
          -               e# subtract 0 or 1 based on above condition from ASCII code
           "1+2* "        e# string containing the operation to perform
                  =~      e# chose the correct operation and evaluate it

在这里在线尝试

由于cosechy,节省了1个字节


1
操作字符串中的空间是多少?
彼得·泰勒

@PeterTaylor在帖子中解释。
Optimizer

9

> <>(鱼),33字节

ib%1-i:1+?\~n;
5a*)?*+40.\b%1-0@i

相当简单明了,几乎没有花招/优化。

说明:

  • 信息:i=下一个输入字符的代码点,-1如果到达输入结束;a= 10; b= 11; )=>
  • i第一个输入字符的代码点,
  • b%1- top_of_stack mod 11 - 1面具48 ('.') , 56 (':')1 , 2
  • i:1+?\~n; 如果到达输入结尾,则打印最后的结果并终止
  • 除此以外:
  • b%1- 屏蔽输入到 1 , 2
  • 0@下推0两个数字
  • i5a*)读取下一个输入并将其掩盖以0 , 1进行比较50
  • 如果1':')将顶部两个元素相乘,则创建堆栈[0产品]
  • 始终添加创建堆栈的前两个元素,[0 sum]或者[0+product=product]
  • 40.跳(循环)回到位置(4,0),我们的观点4i:1+?\~n;

8

Haskell,73 65字节

一个简单的解决方案,利用堆栈中不超过2个元素的事实。

[x,y]#'.'=[x+y]
[x,y]#_=[x*y]
s#'.'=1:s
s#_=2:s
f=head.foldl(#)[]

5

C,104字节

k[2],n;f(char*c){for(n=0;*c;)k[n]=*c++-58?n>1?n=0,*k+k[1]:1:n>1?n=0,*k*k[1]:2,k[1]=n++?k[1]:0;return*k;}

好吧,这太长了。


5

Pyth,25个 24字节

eu?]?.xGHsGtG+GhHmqd\:zY

通过研究@isaacg的解决方案有一个想法。但是我正在使用堆栈。

在线演示测试套件

说明

我要做的第一件事是将输入字符串转换为0和1。将A "."转换为a 0,将a ":"转换为1

mqd\:z   map each char d of input to (d == ":")

然后,我减少此数字列表:

eu?]?.xGHsGtG+GhHmqd\:zY
 u                     Y   start with the empty stack G = []
                           for each H in (list of 0s and 1s), update G:
                              G = 
    ?.xGHsG                      product of G if H != 0 else sum of G
   ]                             wrapped in a list 
  ?        tG                 if G has more than 1 element else
             +GhH                G + (H + 1)
e                         take the top element of the stack

4

JavaScript(ES6),65

我们仅使用堆栈中的2个单元格。

开始将值放入s [0]。
然后,在输入字符串的每个奇数位置(从0开始计数),在s [1]中放置一个值。
在每个偶数位置,执行一个calc(加或乘)并将结果存储在s [0]中。

因此,请忽略堆栈,仅使用两个变量a和b。

f=s=>[...s].map((c,i)=>(c=c>'.',i&1?b=1+c:i?c?a*=b:a+=b:a=1+c))|a

快速测试

for(i=0;i<128;i++)
{
  b=i.toString(2).replace(/./g,v=>'.:'[v]).slice(1)
  if(b.length&1) console.log(b,f(b))
} 

输出量

"." 1
":" 2
"..." 2
"..:" 1
".:." 3
".::" 2
":.." 3
":.:" 2
"::." 4
":::" 4
"....." 3
"....:" 2
"...:." 4
"...::" 4
"..:.." 2
"..:.:" 1
"..::." 3
"..:::" 2
".:..." 4
".:..:" 3
".:.:." 5
".:.::" 6
".::.." 3
".::.:" 2
".:::." 4
".::::" 4
":...." 4
":...:" 3
":..:." 5
":..::" 6
":.:.." 3
":.:.:" 2
":.::." 4
":.:::" 4
"::..." 5
"::..:" 4
"::.:." 6
"::.::" 8
":::.." 5
":::.:" 4
"::::." 6
":::::" 8

-2:f=s=>[(c=s[i]>'.',i&1?b=1+c:+i?c?a*=b:a+=b:a=1+c)for(i in s)]|a
nderscore 2015年

@nderscore至少在我的浏览器上不起作用。for(i in s)除了索引外还提供了其他属性
edc65

它在Firefox 37.0.2中为我工作。尝试在一个干净的浏览器选项卡中运行它。看来stackexchange为字符串添加了其他属性(在stub.en.js中)
nderscore 2015年

3

Pyth,27个字节

Jmhqd\:zu?*GhHteH+GhHctJ2hJ

一堆?谁需要堆栈。

                       Implicit: z is the input string.
Jmhqd\:z               Transform the string into a list, 1 for . and 2 for :
                       Store it in J.
u            ctJ2hJ     Reduce over pairs of numbers in J, with the
                       first entry as initial value.
 ?    teH               Condition on whether the second number is 1 or 2.
  *GhH                  If 1, update running total to prior total times 1st num.
         +GhH           If 2, update running total to prior total plus 1nd num.

示范。


1
天才。同时我实现了一个堆栈(32字节)。:-(
雅各布2015年

3

视网膜105 75 73字节

我的第一个Retina程序!(感谢MartinBüttner节省了2个字节,更不用说首先发明了该语言。)

每行应放在一个单独的文件中;或者,您可以将它们全部放在一个文件中并使用该-s标志。该<empty>表示法表示一个空文件/行。

^(a+;)?\.
$1a;
^(a+;)?:
$1aa;
;(a+;)\.
$1
(a+);aa;:
$1$1;
)`;a;:
;
;
<empty>
a
1

mbomb007的回答启发,但我采用了另一种方法。一个主要区别是,我将堆栈构建在圆角字符串的前面(堆栈顶部朝右)。这样可以很容易地将符号转换为相应的数字。我还使用a代替1,仅在最后将其交换出去,以避免解析像序列中的歧义$1a。如果像这样的答案aaaaaa可以接受为一元数,则可以省去最后两行/文件以节省4个字节。

说明:

^(a+;)?\.
$1a;

如果堆栈((a+;)?)上有0或1个项目,后跟一个句点(\.),则匹配;如果是这样,它将用a;(即按1)替换句点。

^(a+;)?:(.*)
$1aa;$2

如果堆栈中有0或1个项目,然后是冒号,则匹配。如果是这样,它将替换冒号aa;(即按2)。

;(a+;)\.
$1

如果在堆栈上有两个项目后跟一个句点,则匹配。删除项目之间的句点和分号,从而添加它们。

(a+);aa;:
$1$1;

如果堆栈上有两个项目,则匹配,最高的是2,然后是冒号。删除冒号和2,并将另一个数字重复两次,从而将其乘以2。

)`;a;:
;

如果堆栈中有两个项目,则正则表达式匹配,其顶部为1,后跟冒号。删除冒号和1,其他数字保持不变(即乘以1)。

)`指示循环结束。如果对该字符串进行了任何更改,则控件将返回到程序顶部并再次运行替换。如果字符串停止更改,我们将替换所有的句点和冒号,剩下的就是清除...

;
<empty>

删除剩余的分号。

a
1

将所有a转换为1。同样,如果一元数被允许使用任何符号,则此步骤是不必要的。


那么,是否将循环的开始假定为第一个文件?
mbomb007'9

@ mbomb007是的。我已经在文档中看到了这一点,但是在Martin提醒我之前就忘记了。;)
DLosc

2

Rust,170个字符

fn f(s:String)->i32{let(mut a,mut b)=(-1,-1);for c in s.chars(){if b!=-1{a=match c{'.'=>a+b,':'=>a*b,_=>0};b=-1}else{b=match c{'.'=>1,':'=>2,_=>0};if a==-1{a=b;b=-1}};}a}

更有力的证据证明,Rust在打高尔夫球时绝对可怕。完整的完整代码:

#[test]
fn it_works() {
    assert_eq!(dotty_ungolfed("::...:.:.".to_string()), 9);
    assert_eq!(f("::...:.:.".to_string()), 9);
}

fn dotty_ungolfed(program: String) -> i32 {
    let (mut a, mut b) = (-1, -1);
    for ch in program.chars() {
        if b != -1 {
            a = match ch { '.' => a + b, ':' => a * b, _ => panic!() };
            b = -1;
        } else {
            b = match ch { '.' => 1, ':' => 2, _ => panic!() };
            if a == -1 { a = b; b = -1; }
        }
    }
    a
}

fn f(s:String)->i32{let(mut a,mut b)=(-1,-1);for c in s.chars(){if b!=-1{a=match c{'.'=>a+b,':'=>a*b,_=>0};b=-1}else{b=match c{'.'=>1,':'=>2,_=>0};if a==-1{a=b;b=-1}};}a}

这是我在此过程中使用的一个有趣技巧。您可以通过让if if / else语句返回一个立即被丢弃的值来删除if / else语句中的字符,这意味着您只需要一个分号而不是两个分号。

例如,

if foo {
    a = 42;
} else {
    doSomething(b);
}

可以变成

if foo {
    a = 42
} else {
    doSomething(b)
};

通过去除分号来保存字符。


2

Haskell, 88 81 79字节

(h:t)![p,q]|h=='.'=t![p+q]|1<2=t![p*q]
(h:t)!s|h=='.'=t!(1:s)|1<2=t!(2:s)
_!s=s

似乎有人在Haskell解决方案上击败了我,不仅如此,他们的解决方案还比我的解决方案短。这很糟糕,但是,我认为没有理由不发表我的想法。


2

APL(50)

我在这里有一个很大的劣势,因为APL不是基于堆栈的语言。我最终不得不减少滥用以缩短程序。

{⊃{F←'.:'⍳⍺⋄2>⍴⍵:F,⍵⋄((⍎F⌷'+×')/2↑⍵),2↓⍵}/(⌽⍵),⊂⍬}

内部函数在左侧接受一个“命令”,在右侧接受一个堆栈,并将其应用并返回堆栈。外部函数将其从字符串开始减少,从空堆栈开始。

说明:

  • (⌽⍵),⊂⍬:减少的初始列表。⊂⍬是一个装箱的空列表,表示堆栈,(⌽⍵)是输入的反向。(在列表上从右到左应用减法,因此字符串将从右到左进行处理。事先反转输入将使其以正确的顺序应用字符。)

  • {... }:内部功能。它在右侧使用堆栈,在左侧使用字符,然后返回修改后的堆栈。

    • F←'.:'⍳⍺:字符串中字符的索引,.:根据值,它将为1或2。
    • 2>⍴⍵:F,⍵:如果2大于当前堆栈的大小,只需将当前值附加到堆栈。
    • : 除此以外,
      • 2↓⍵:从堆栈中删除前两个项目
      • (... )/2↑⍵:减少它们上的给定函数,然后将其添加到堆栈中。
      • ⍎F⌷'+×':该函数是+(加法)或×(乘法),由选择F
  • :最后,返回堆栈中最顶层的项目


2

红宝石-96个字符

这里有点有趣eval

除此之外,我假设第一个字符之后,堆栈将始终变为2,math,2,math,...。这使我可以通过一次抓取两个char来使用更少的代码-我永远不必弄清楚确定字符是数学还是数字。这是位置。

x,m=$<.getc>?.?2:1
(b,f=m.split //
b=b>?.?2:1
x=f ?eval("x#{f>?.??*:?+}b"):b)while m=gets(2)
p x

取消高尔夫:

bottom_of_stack = $<.getc > '.' ? 2 : 1 # if the first char is ., 1, else 2
two_dots = nil
while two_dots = gets(2) do # get the next 2 chars
  number_char, math_char = two_dots.split //
  number = number_char > '.' ? 2 : 1
  if math_char
    math = math_char > '.' ? '*' : '+'
    # so bottom_of_stack = bottom_of_stack + number ...
    # or bottom_of_stack = bottom_of_stack * number
    bottom_of_stack = eval("bottom_of_stack #{math} number")
  else
    # if there's no math_char, it means that we're done and 
    # number is the top of the stack
    # we're going to print bottom_of_stack, so let's just assign it here
    bottom_of_stack = number
  end
end
p bottom_of_stack  # always a number, so no need for `puts`

2

TI-BASIC,78 73 70 69 66字节

Input Str1
int(e^(1=inString(Str1,":
For(A,2,length(Str1),2
Ans+sum({Ans-2,1,1,0},inString("::..:",sub(Str1,A,2
End
Ans

TI-BASIC擅长于单行代码,因为右括号是可选的。相反,这是一种糟糕的语言,其中需要存储多个值,因为存储到变量需要两到四个字节的空间。因此,目标是在每行上尽可能多地写入。对于任何类型的字符串操作,TI-BASIC(对于标记语言)也很糟糕。即使读取子字符串也很长。

技巧包括:

  • int(e^([boolean]代替1+(boolean; 保存一个字节
  • 列表的部分总和,而不是列表切片(需要存储到列表中):节省3个字节

从Ans输入,例如".:.":prgmDOTTY保存4个字节,应该没问题。
MI赖特

@Wright我使用Ans将数字存储在堆栈中。
lirtosiast,2015年

我的意思是,一开始就摆脱了第一行,然后将第二行更改为1+(":"=sub(Ans,1,1
MI Wright

1
我需要在采用Ans的循环中使用Str1,所以我无法避免将字符串保留在Ans中。从Ans将其存储到Str1不会节省任何空间。
lirtosiast

1

走, 129 115 112字节

func m(s string){a,b:=0,0;for c,r:=range s{c=int(r/58);if b>0{a=a*b*c+(a+b)*(c^1);b=0}else{b,a=a,c+1}};print(a)}

(有点)不满意:

func m(s string){
    // Our "stack"
    a, b := 0, 0
    // abusing the index asignment for declaring c
    for c, r := range s {
        // Ascii : -> 58, we can now use bit fiddeling
        c = int(r / 58)
        if b > 0 {
            // if r is :, c will be 1 allowing a*b to pass through, c xor 1 will be 0
            // if r is ., c xor 1 will be 1 allowing a+b to pass through
            a = a*b*c + (a+b)*(c^1)
            b = 0
        } else {
            b, a = a, c+1 // Since we already know c is 0 or 1
        }
    }
    print(a)
}

在此处在线尝试:http : //play.golang.org/p/B3GZonaG-y


1

Python 3、74

x,*s=[1+(c>'.')for c in input()]
while s:a,b,*s=s;x=[x*a,x+a][-b]
print(x)

首先,将输入列表转换为1和2的序列,并将第一个值作为初始值x。然后,一次从的开头取两个元素s,取第一个数字,并根据第二个数字是1还是2与当前数字相加或相乘。


1

好吧,这是如此简单的操作,由操作人员精心设计(有意)

只是...

带括号的表达式转换为后缀* / +操作

代码:C(80字节)

int f(char*V){return*(V-1)?f(V-2)*(*V==58?*(V-1)/29:1)+(*V&4)/4**(V-1)/29:*V/29;}
  • 应该从字符串尾部调用该函数,如下所示:f(V + 10)其中V =“。:..:。:.. ::”

输入

长度= 2n + 1类型为char'的向量V。要么 ':'

输出量

整数k

功能

  • k =(V [1] op(V [3])V [2])op(V [5])V [4]...。

  • op(x):(x ='。')-> +,(x =':')-> *


模拟:

在这里尝试


您如何假设字符串(*(V-1))之前的字节为零?
nutki

当您分配一个新向量时,其开始总是从空段开始,其结束一个空字符
Abr001am 2015年

1

视网膜,181个 135 129字节

每行应位于单独的文件中。<empty>代表一个空文件。输出为一元。

^\..*
$&1;
^:.*
$&11;
^.
<empty>
(`^\..*
$&1
^:.*
$&11
^.(.*?1+;1+)
$1
^(\..*);(1+)
$1$2;
;1$
;
^(:.*?)(1+).*
$1$2$2;
)`^.(.*?1+;)
$1
;
<empty>

${0}1被使用时,大括号分开$01,否则这将是$01,所述第一匹配组。我尝试使用$001,但这似乎不适用于regex的.NET风格。

编辑:发现$&与相同$0

在伪代码中,这实际上是一个do-while循环,如下所示。我按第一个数字,然后循环:按第二个数字,删除操作(指令),做数学运算,删除运算符。继续循环。请注意,当弹出操作时,这还将在完成所有指令后删除空格。

评论:

^\..*           # Push if .
$&1;
^:.*            # Push if :
$&11;
^.              # Pop op
<empty>


(`^\..*         # Loop, Push #
$&1
^:.*
$&11
^.(.*?1+;1+)    # Pop op
$1


^(\..*);(1+)    # Add if . (move ;)
$1$2;
;1$          # If mul by 1, remove
;
^(:.*?)(1+).*   # Mul if : (double)
$1$2$2;
)`^.(.*?1+;)    # Pop op, End Loop (clean up)
$1
;               # Remove semicolon
<empty>

我在高尔夫方面看到的主要东西是(:)(.*)-> 这样的图案/替换对$1$2,我敢肯定可以(:.*)-> $1(因为您将两个组保持相同的顺序,并且对它们不做任何其他处理)。
DLosc 2015年

我得到了启发,并做出了自己的视网膜答案。感谢您促使我下载这种有趣的语言!
DLosc

@DLosc酷!是的,我还没有真正下载它。我为每个单独的替换使用了一个在线正则表达式替换测试器。
mbomb007'9

0

Python 3,122个字节

x=input()
l=[0,0]
for _ in x:
 t=len(l)-2<2
 l=[[[0,0,l[-2]*l[-1]],l+[2]][t],[[0,0,sum(l)],l+[1]][t]][_=='.']
print(l[-1])

取消高尔夫:

x = input()
l = []
for i in x:
    if i == '.':
        if len(l) < 2: 
            l+=[1]        #True, True = 1,1
        else:
            l=[sum(l)]    #True, True = 1,0
    else:
        if len(l)<2:
            l+=[2]        #False, True = 0,1
        else:
            l=[l[0]*l[1]] #False, False = 0,0
print (l[0])

在python中,您可以像这样引用列表的索引:

list[index]

您可以在其中添加一个布尔值,Trueis 1Falseis 0

# t is True if the length is less than 2, else false.

l=[ 

  # |------- Runs if char is : -------|
  # |------- l<2 -------| |- l>=2 -|

    [ [ 0,0, l[-2]*l[-1] ], l+[2] ] [t],

                                      # |---- Runs if char is . ----| 
                                      # |--- l<2 ---|  |- l>=2 -|

                                        [ [0,0, sum(l)], l+[1] ] [t] ]
                                                                      [_=='.']

在这里在线尝试


0

Perl,77个字节

@o=(0,'+','*');sub d{$_=shift;y/.:/12/;eval'('x s!\B(.)(.)!"$o[$2]$1)"!ge.$_}

扩展:

@o=(0, '+', '*');
sub d{
    $_=shift;
    y/.:/12/;
    eval '(' x s!\B(.)(.)!"$o[$2]$1)"!ge.$_
}

所述@o阵列映射数字来运营。然后,我们用适当的运算符替换数字对,并重新排序为中缀。正则表达式以开头,\B因此我们不匹配第一个字符。的结果s///g告诉我们开始时需要多少个开放的paren。然后,当我们组装完整的中缀表达式时,我们可以对其进行评估。(eval如果您想查看该表达式,请删除)。

这是我用来验证结果的测试工具:

while(<>) {
    my ($a, $b) = m/(.*) (.*)/;
    print d($a), " $b\n";
}

输入是点表达式及其值的列表(问题中提供),输出是{实际,期望的}对。

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.