Parantez ve Köşeli Parantezlerin Tamsayı Olarak Değerlendirilmesi


20

()[]Bu noktaları sağlayan dört karakterden oluşan bir dize alan bir program yazın :

  • Her sol parantezin (eşleşen bir sağ parantez vardır ).
  • Her sol köşeli parantezde [eşleşen bir sağ köşeli parantez bulunur ].
  • Eşleşen parantez ve parantez çiftleri çakışmaz. Örneğin [(]), eşleşen parantezler eşleşen parantezlerde tam olarak bulunmadığından veya tam tersi olduğundan geçersizdir.
  • İlk ve son karakterler eşleşen bir parantez veya parantez çiftidir. Bu yüzden geçerlidir ([]([]))ve [[]([])]geçerli []([])değildir.

( Girdi biçimi için bir dilbilgisi<input> ::= [<input>*] | (<input>*) .)

Her eşleşen parantez ve parantez çifti, negatif olmayan bir tamsayı olarak değerlendirilir:

  • Eşleşen parantez içindeki çiftlerin değerleri toplanır . Boş eşleşmenin ()değeri vardır 0.
  • Eşleşen parantez içindeki çiftlerin değerleri çarpılır . Boş eşleşmenin []değeri vardır 1.

( Bir sayının toplamı veya ürünü aynı sayıdır.)

Örneğin, ([](())([][])[()][([[][]][][])([][])])parçalanabilir ve şu şekilde değerlendirilebilir 9:

([](())([][])[()][([[][]][][])([][])])    <input>
(1 (0 )(1 1 )[0 ][([1 1 ]1 1 )(1 1 )])    <handle empty matches>
(1 0   2     0   [(1     1 1 )2     ])    <next level of matches>
(1 0   2     0   [3           2     ])    <and the next>
(1 0   2     0   6                   )    <and the next>
9                                         <final value to output>

Başka bir örnek:

[([][][][][])([][][])([][][])(((((([][]))))))]    <input>
[(1 1 1 1 1 )(1 1 1 )(1 1 1 )((((((1 1 ))))))]
[5           3       3       (((((2     )))))]
[5           3       3       ((((2       ))))]
[5           3       3       (((2         )))]
[5           3       3       ((2           ))]
[5           3       3       (2             )]
[5           3       3       2               ]
90                                                <output>

Programınızın tüm girdi dizesi tarafından temsil edilen tamsayıyı değerlendirmesi ve yazdırması gerekir. Girişin geçerli olduğunu varsayabilirsiniz. Bayt cinsinden en kısa kod kazanır.

Program yerine, bir dize alan ve tamsayıyı yazdıran veya döndüren bir işlev yazabilirsiniz.


Python sunumu adına açıklama istemek: Yalnızca program mı, yoksa işlevler / dönüş değeri iyi mi?
Sp3000

O zaman soruyu düzenlemek iyi olabilir. Önceki bir soruda, soruda "bir program yaz" yazdığında işlevlerin geçerli olmadığı söylendi.
Reto Koradi

Yanıtlar:


11

CJam, 23

q"])(""1]:*0]:+["4/ers~

Dennis için BÜYÜK kredi ile! Çevrimiçi deneyin

Açıklama:

Program, girişi bir CJam ifadesine dönüştürür ve sonra değerlendirir.
[…]olur […1]:*(1'i ekleyin ve çarpın)
(…)olur […0]:+(0'ı ekleyin ve ekleyin)

q              read input
"])("          characters we want to replace
"1]:*0]:+["    replacement strings, concatenated
4/             split into strings of length 4: ["1]:*" "0]:+" "["]
er             replace (transliterate) the 3 characters with the 3 strings
s              convert the result (mixed characters and strings) to string
~              evaluate

1
Harf çevirisi 4 bayt tasarrufu sağlar:q"])(""1]:*0]:+["4/ers~
Dennis

2
@Dennis whaaa! Bu delilik, yapabilirsin ??
aditsu

3
Sen soruyorsun bana ? : P
Dennis

4
@Dennis CJam'ın yaratıcısı böyle bir özelliğin varlığını nasıl bilebilir?
Doktor

8

Yaygın Lisp - 98

(lambda(s)(eval(read-from-string(#1=ppcre:regex-replace-all"\\["(#1#"]"(#1#"\\("s"(+")")")"(*"))))
  1. Değiştir (tarafından(+
  2. Değiştir [tarafından(*
  3. Değiştir ]tarafından)
  4. Dizeden oku
  5. Eval

Bu, cl-ppcrekütüphanenin geçerli lisp görüntüsüne yüklenmesini gerektirir .

açıklama

Fonksiyonlar *ve +değişkendir ve argüman verilmediğinde nötr değerlerini döndürürler. Örnekleriniz için, değerlendirilen lisp formu aşağıdaki gibidir:

(+ (*) (+ (+)) (+ (*) (*)) (* (+)) (* (+ (* (*) (*)) (*) (*)) (+ (*) (*))))
=> 9

ve

(* (+ (*) (*) (*) (*) (*)) (+ (*) (*) (*)) (+ (*) (*) (*))
   (+ (+ (+ (+ (+ (+ (*) (*))))))))
=> 90

Normal ifadeler olmadan - 183 bayt

(lambda(s)(do(r(x(coerce s'list))c)((not x)(eval(read-from-string(coerce(reverse r)'string))))(setq c(pop x))(push(case c(#\[ (push #\* r)#\()(#\] #\))(#\( (push #\+ r) #\()(t c))r)))

Hadi, Lisp - 16 bayt (deneysel)

+((<r*([<r)]<rRE

Diğer diller o kadar keskindir ki, daha kısa string manipülasyonları için Common Lisp tabanlı kendi golf dilimi yapmaya cazipim. Şu anda spesifikasyon yok ve eval fonksiyonu şu şekildedir:

(defun cmon-lisp (expr &rest args)
  (apply
   (lambda (s)
     (let (p q)
       (loop for c across expr
             do (case c
                  (#\< (push (pop p) q))
                  (#\r
                   (let ((a1 (coerce q 'string)) (a2 (coerce p 'string)))
                     (setf p nil
                           q nil
                           s
                             (cl-ppcre:regex-replace-all
                              (cl-ppcre:quote-meta-chars a1) s a2))))
                  (#\R
                   (setf s
                           (if (string= s "")
                               nil
                               (read-from-string s))))
                  (#\E (setf s (eval s)))
                  (t (push c p))))
       s))
   args))

Testler:

(cmon-lisp "+((<r*([<r)]<rRE" "([] [] ([] []))")
=> 4
  • örtük bir argüman denir sve iki yığın, pve q.
  • kaynak koddaki karakterlere itilir p.
  • <: 'den çıkar pve iter q.
  • r: skarakter içerisindeki qkarakterlerden yerine karakter ( karakter dizesi olmalıdır) p; sonuç s; pve qboşaltılır.
  • R: dizeden okuma s, sonucu değişkende saklama s.
  • E: eval formu s, sonucu depola s.

1
Lisp'in parantez ile bir şey yapmak için nasıl kullanıldığı Funyy.
Syd Kerckhove

@SydKerckhove Yorumunuz bana uygun bir Clojure cevabı düşündürüyor. Çok teşekkürler!
coredump

6

Pyth, 35 34 33 bayt

L?*F+1yMbqb+YbsyMbyvsXzJ"])"+R\,J

Gösteri.

@ Jakube sayesinde 1 bayt.

Girdi ayrıştırılarak başlıyoruz. Giriş formatı Python'a yakın, ancak tam olarak değil. Her parantez veya parantez grubundan sonra virgül kullanmamız gerekir. Köşeli parantezli bir grubun sonundaki virgül gereksizdir, ancak zararsızdır. Bunu yapmak için şu kodu kullanıyoruz:

vsXzJ"])"+R\,J
  X               Translate
   z              in the input
     "])"         the characters "])"
    J             which we will save to J to
             J    J
         +R\,     with each character mapped to itself plus a ",".
 s                Combine the list to a string.
v                  Evaluate as a Python literal.

Bu ,, dizenin sonunda, tüm nesneyi bir demet içine saran bir ekstra bırakacaktır , ancak bu zararsızdır, çünkü demet toplanacaktır ve bu nedenle elemanına eşit bir değere sahiptir.

Dize ayrıştırıldığına göre, değerini bulmalıyız. Bu, yayrıştırılmış nesne üzerinde çağrılan kullanıcı tanımlı bir işlev kullanılarak yapılır . işlev aşağıdaki gibi tanımlanır:

L?*F+1yMbqb+YbsyMb
L                     Define a function, y(b), which returns the following:
 ?       qb+Yb        We form a ternary whose condition is whether the input, b,
                      equals the inputplus the empty list, Y. This is true if
                      and only if b is a list.
      yMb             If so, we start by mapping y over every element of b.
  *F+1                We then take the product of these values. The +1 ensures
                      that the empty list will return 1.
                yMb   Otherwise, we start by mapping y over every element of b.
               s      Then, we sum the results.

@ Jakube Doğru, tekli toplamın bir etkisi yoktur.
isaacg

3

Emacs Lisp, 94

Biçim çok lispy görünüyor, bu yüzden basit bir dönüşüm işe yarayabilir düşündüm:

(defun e()(format-replace-strings'(("("."(+")("["."(*")("]".")")))(eval(read(buffer-string))))

Ara biçim şuna benzer (sorudaki örnek için):

(+(*)(+(+))(+(*)(*))(*(+))(*(+(*(*)(*))(*)(*))(+(*)(*))))

Toplama ve çarpma işleminin boş bir argüman listesiyle istediğimizi yapması bize yardımcı oluyor.

Degolfed ve interaktif, zevk için oynamak:

(defun paren_eval()
  (interactive "*")
  (format-replace-strings '(("(" . "(+")
                            ("[" . "(*")
                            ("]" . ")")))
  (eval (read (buffer-string)))
)

Daha yakından okumalıydım - Common Lisp çözümü tamamen aynı yaklaşımı benimsiyor!
Toby Speight

1
Daha fazla Emacs Lisp cevabına ihtiyacımız var !. Btw, ben saymadım ama bir lambda kullanarak, parametre olarak bir dize alarak ve kaldırma interactive (buffer-string yerine, read-from-string kullanın) kullanarak biraz daha golf olabilir .
coredump

2

Retina , 111 bayt

[\([](1+x)[]\)]
$1
\[]
1x
\(\)
x
(\[a*)1(?=1*x1*x)
$1a
a(?=a*x(1*)x)
$1
(\[1*x)1*x
$1
)`(\(1*)x(?=1*x)
$1
[^1]
<empty line>

Tekli olarak çıktı verir.

Her satır kendi dosyasına gitmelidir ancak kodu -sbayraklı tek bir dosya olarak çalıştırabilirsiniz . Örneğin:

> retina -s brackets <input_1
111111111

Açıklama daha sonra gelir.


2

Java, 349 karakter

Basit bir özyinelemeli yaklaşım. Dizenin, programı çağırmak için kullanılan ilk bağımsız değişken olmasını bekler.

import java.util.*;class K{int a=0,b;String c;public static void main(String[]a){K b=new K();b.c=a[0];System.out.print(b.a());}int a(){switch(c.charAt(a++)){case'(':b=0;for(int a:b())b+=a;break;case'[':b=1;for(int a:b())b*=a;}a++;return b;}List<Integer>b(){List d=new ArrayList();char c;while((c=this.c.charAt(a))!=']'&&c!=')')d.add(a());return d;}}

Expanded:

import java.util.*;

class K {
    int a =0, b;
    String c;
    public static void main(String[] a){
        K b = new K();
        b.c = a[0];
        System.out.print(b.a());
    }
    int a(){
        switch (c.charAt(a++)){
            case '(':
                b =0;
                for (int a : b())
                    b += a;
                break;
            case '[':
                b =1;
                for (int a : b())
                    b *= a;
        }
        a++;
        return b;
    }
    List<Integer> b(){
        List d = new ArrayList();
        char c;
        while ((c= this.c.charAt(a)) != ']' && c != ')')
            d.add(a());
        return d;
    }
}

2

Perl 5, 108

Yeniden yazma ve değerlendirme yerine tercüman olarak yapılır. Büyük bir gösteri değil, ama yine de yazmak için eğlenceli.

push@s,/[[(]/?[(ord$_&1)x2]:do{($x,$y,$z,$t)=(@{pop@s},@{pop@s});
[$t?$x*$z:$x+$z,$t]}for<>=~/./g;say$s[0][0]

Un-golfed:

# For each character in the first line of stdin
for (<> =~ /./g) {
    if ($_ eq '[' or $_ eq '(') {
        # If it's an opening...
        # ord('[') = 91 is odd, ord('(') = 40 is even
        push @stack, [ ( ord($_) & 1) x 2 ];
        # so we will push [1, 1] on the stack for brackets and [0, 0] for parens.
        # one of these is used as the flag for which operator the context is, and
        # the other is used as the initial (identity) value.
    } else {
        # otherwise, assume it's a closing
        ($top_value, $top_oper) = @{ pop @stack };
        ($next_value, $next_oper) = @{ pop @stack };
        # merge the top value with the next-to-top value according to the
        # next-to-top operator. The top operator is no longer used.
        $new_value = $next_oper
            ? $top_value * $next_value
            : $top_value + $next_value
        push @stack, [ $new_value, $next_oper ];
    }
}

say $stack[0][0]; # print the value remaining on the stack.

2

Python, 99

Çeşitli yöntemler denedim ama alabildiğim en kısa şey temelde sadece bir değiştirme ve değerlendirme. ,Python ayrıştırabildiğinden [1,2,]ve son takip eden virgül her şeyi bir demet halinde koyduğundan, tüm izleri bırakabileceğimi bulmak hoş bir sürpriz oldu . Sadece olmayan diğer basit parçası olacak ord(c)%31%7farklı karakterler dışarı ayırmak için (bu değerlendirir için 2, 3, 1, 0için (, ), [, ]sırasıyla)

F=lambda s:eval(''.join(["],1),","reduce(int.__mul__,[","sum([","]),"][ord(c)%31%7]for c in s))[0]

1
Bu bir program olarak çalışmaz, değil mi? Soru bir program ister, bu yüzden bir işlev sağlamanın gereksinimleri karşıladığını düşünmüyorum. En azından insanların bana en son ne zaman soruda "program" dediğinde bir işlev sunduğumu söyledi. :)
Reto Koradi

1

Java, 301

benim de doğada özyinelemeli olmasına rağmen, TheNumberOne'un cevabından biraz farklı bir yaklaşım. Giriş komut satırından alınır. Void yöntemi, artık gerekli olmayan karakterleri kaldırırken birkaç bayt kaydeder.

enum E{I;String n;public static void main(String[]r){I.n=r[0];System.out.print(I.e());}int e(){int v=0;if(n.charAt(0)=='('){for(s("(");n.charAt(0)!=')';)v+=e();s(")");}else if(n.charAt(0)=='['){v=1;for(s("[");n.charAt(0)!=']';)v*=e();s("]");}return v;}void s(String c){n=n.substring(1+n.indexOf(c));}}

genişletilmiş:

enum EvaluatingParenthesesAndBrackets{
    AsIntegers;
    String input;
    public static void main(String[]args){
        AsIntegers.input=args[0];
        System.out.print(AsIntegers.evaluate());
    }
    int evaluate(){
        int value=0;
        if(input.charAt(0)=='('){
            for(substringAfterChar("(");input.charAt(0)!=')';)
                value+=evaluate();
            substringAfterChar(")");
        }
        else if(input.charAt(0)=='['){
            value=1;
            for(substringAfterChar("[");input.charAt(0)!=']';)
                value*=evaluate();
            substringAfterChar("]");
        }
        return value;
    }
    void substringAfterChar(String character){
        input=input.substring(1+input.indexOf(character));
    }
}

1

Python, 117 110 109 bayt

def C(s,p=[0]):
 m=r=s[p[0]]=='[';p[0]+=1
 while s[p[0]]in'[(':t=C(s,p);r=r*t*m+(r+t)*(1-m)
 p[0]+=1;return r

Mücadele ettiğim bir yön, işlevin temel olarak iki dönüş değerine sahip olmasıdır: ürün / toplam ve dizgideki yeni konum. Ama sadece sonucu döndüren bir fonksiyona ihtiyacım var, bu yüzden bir tuple döndürmek işe yaramaz. Bu sürüm, işlevi işlevden geri geçirmek için bir "başvuru" bağımsız değişkeni (bir öğeli liste) kullanır.

Konum için genel bir değişken kullanan daha kısa bir sürümü (103 bayt) var. Ancak bu sadece ilk çağrıda işe yarayacaktır. Ve sadece bir kez çalışan bir işlev biraz balık gibi görünüyor. Kod golf için kabul edilebilir olacağını emin değilim.

Algoritma basit bir özyineleme. Ürün / toplamı güncelleyen ifade için birkaç varyasyon denedim. Tam olarak aynı uzunlukta birkaç sürüm buldum, ancak hiçbiri daha kısa olmadı.

Bunu, değerlendirilen bir ifadeye dönüştüren yaklaşımın muhtemelen kazanacağını umuyordum. Ama dedikleri gibi: "Yinelemek insandır, ilahi olanı tekrarlamaktır."


Fonksiyonlara artık açıkça izin veriliyor :)
Calvin'in Hobileri

@ Calvin'sHobbies Genel olarak merak ettiğim bir kural sorusu var, ancak burada devreye girebilir: Bir çözüm işlev olarak uygulanırsa, bu işlev tek bir seferde birden fazla çağrılabileceği anlamına mı geliyor? Örneğin, yalnızca ilk çağrıda doğru şekilde başlatılan bir global değişken kullansaydı, bu ... yanlış olur mu?
Reto Koradi

@Retro Evet diyebilirim, yanlış. İşlev, yeniden yorumlamadan istediğiniz sayıda çalışmalıdır.
Calvin'in Hobileri

1

Clojure - 66 bayt

([] (()) ([] []) [()] [([[] []] [] []) ([] [])])Geçerli bir Clojure formu olduğuna dikkat edin . Yani:

#(letfn[(g[x](apply(if(list? x)+ *)(map g x)))](g(read-string %)))
  • Bu bir dize alan, onu okuyan ve veren anonim bir fonksiyondur g.
  • Yerel gfonksiyonu uygulamak +veya *çağırma sonucuna gBağımsız değişkenlerinin alt elemanlarında.
  • Özyinelemenin temel durumu biraz incedir: xboş bir sırayla ulaşılır ; (map g x)döner nilve applyişlem için nötr bir değer verir.

0

JavaScript (ES6), 116 bayt

s=>+[...s].reduce((t,c)=>((x=c==']')||c==')'?t[1].push(t.shift().reduce((a,b)=>x?a*b:a+b,+x)):t.unshift([]),t),[[]])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.