Operatör önceliği: Ne kadar yanlış olabilirim?


65

Bir ifadem olduğunu söyle:

9 * 8 + 1 - 4

Bu ifade, operatör önceliğine bağlı olarak altı farklı şekilde yorumlanabilir:

(((9 * 8) + 1) - 4) = 69 (* + -)
((9 * 8) + (1 - 4)) = 69 (* - +)
((9 * (8 + 1)) - 4) = 77 (+ * -)
(9 * ((8 + 1) - 4)) = 45 (+ - *)
((9 * 8) + (1 - 4)) = 69 (- * +)
(9 * (8 + (1 - 4))) = 45 (- + *)

Bir geliştirici olduğumu ve öncelik tablolarını vb. Ezberlemek istemiyorum, bu yüzden sadece tahmin edeceğim.

Bu durumda, en büyük hata marjı 45-77 olacaktır, bu 32'nin farkıdır.

Meydan okuma

Sayı ve aşağıdakilerden oluşan bir ifade verilen +, -, *, /(tamsayı bölme) ve %operatörlerin öncelik göre, çıktı o ifadesi için en büyük ve en küçük değerin mutlak fark.

Özellikler

  • Giriş ifadesi parantez içermez ve her operatör sola dayalıdır.
  • Giriş ifadesi yalnızca negatif olmayan tam sayılar içerecektir. Bununla birlikte, alt ifadeler negatifleri değerlendirebilir (örneğin 1 - 4).
  • İfadeyi herhangi bir makul formatta alabilirsiniz. Örneğin:
    • "9 * 8 + 1 - 4"
    • "9*8+1-4"
    • [9, "*", 8, "+", 1, "-", 4]
    • [9, 8, 1, 4], ["*", "+", "-"]
  • Giriş en az 1 ve en fazla 10 operatör içerecektir.
  • 0'a bölünen veya modulo içeren ifadeler dikkate alınmamalıdır.
  • Moduloya negatif operandlar verilmeyeceğini varsayabilirsiniz.

Test Kılıfları

9 * 8 + 1 - 4             32
1 + 3 * 4                  3
1 + 1                      0
8 - 6 + 1 * 0              8
60 / 8 % 8 * 6 % 4 * 5    63

1
@AndersKaseorg %İkinci örneğinizde iki farklı önceliğe sahipmiş gibi davranıyorsunuz .
Esolanging Fruit,

1
Altıdan üçü diğer ikisi gibi aynıdır. Bu altı gerçek değil üç dava açar.
user207421

3
%operatör negatif sayılarla nasıl çalışır? C veya Python ya da başka bir şey gibi mi?
tsh

8
Sadece, "ve ben tembelim" bölümünü tanımına eklemek zorunda değilsin. Sadece bir geliştirici olduğunu söyleyerek yeter. :)
Gryphon

1
@tsh Herhangi bir davranış. Ne istersen onu yap. Sen edebilirsiniz iblisler Burnumdan uçurabileceğin .
Esolanging Fruit

Yanıtlar:


27

Python 2 , 171 156 bayt

lambda a:max(e(a))-min(e(a))
u=')%s('
def e(a,t=u):
 try:b=[eval(a)]
 except:b=[]
 return sum([e('(%s)'%a.replace(o,t%o),u%t)for o in"+-*/%"if' '+o in a],b)

Çevrimiçi deneyin!

Nasıl çalışır

Her bir operatörü, farklı öncelikleri simüle etmek için (mümkün olan tüm yollarla) farklı sayıda dışa bakan parantez çifti ile çevreleriz ve yapabileceğimiz bir ifadeyi almak için tüm dizenin etrafına yeterince içe bakan parantez çiftleri sarılır eval. Örneğin,

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

alırız

9 * 8 + 1 - 4(((9 ))*(( 8 )+( 1 )))-((( 4)))= 77.


Bir köşeli parantez tabakasını kaldırmak için ordışını hareket ettirerek 2 bayttan tasarruf edebilirsiniz sum: sum([...],[])or[eval(a)]yerinesum([...]or[[eval(a)]],[])
Strigoides

@Strigoides Eşdeğer olmadığını düşünüyordum, çünkü sumargümanı boş olmadan boş olabilir - ancak, aslında iyi, çünkü evalbu durumda başarısız olmalı. Teşekkürler.
Anders Kaseorg

8

Jöle , 126 bayt

"Operatör Önceliği? Parantez? Pah, buna kimin ihtiyacı var?" - Jelly'i bir operatör önceliği mücadelesi için kullanmanın zorlukları.

⁾[]i$€Ḥæ%3+\¬œp¹Ḋ€
ǵḟØDO%9µÐṀṪɓœṣ⁹,ṚÑj@¥/
ǵVṾµ1ĿFḟØDḟ”-Lµ?ÐL
5Ḷx@€“]“[”ż⁸j/€,@y³Fɓ³i@€Ṁ’x@“[“]”jÇ
“+_×:%”Œ!Ç€µṾL_L’ỊµÐfV€ṢIS

Çevrimiçi deneyin!

Giriş bir dize olarak alınmıştır, örneğin "1 + 2_3 × 4: 5% 6". Not çarpma işlemi "*" yerine "×", bölme "/" yerine ":" ve çıkarma "-" yerine "_" kullanır.

Nasıl Çalışır Program üç bölüme ayrılır: farklı operatör önceliğinin tüm ifadelerini üretmek, bunları değerlendirmek ve maksimum ve minimum arasındaki farkı döndürmek.

Tüm ifadeler şu kodla üretilir:

5Ḷx@€“]“[”ż⁸j/€,@y³Fɓ³i@€Ṁ’x@“[“]”jÇ (4) helper link: returns all outputs given a permutation. Input e.g. "_+:×%"
5Ḷx@€“]“[”           - repeat outer brackets to get ["",""],["]","["],["]]","[["],["]]]","[[["],["]]]]","[[[["]
          ż⁸j/€      - insert the operations in to get "_","]+[","]]:[[","]]]×[[[","]]]]%[[[["
               ,@    - turn this into a mapping equivalent to "_"↦"_","+"↦"]+[",":"↦"]]:[[","×"↦"]]]×[[[","%"↦"]]]]%[[[["
                 y³F - use this mapping to get the right number of outward brackets on each operation. e.g. "1]+[3]]]×[[[4"
ɓ³i@€Ṁ’x@“[“]”j      - add the right number of brackets to the end to get e.g."[[[1]+[3]]]×[[[4]]]"
               Ç     - this calls the link which evaluates the expression
“+_×:%”Œ!Ç€                          (5a) main link. Input e.g. "1+3×4"
“+_×:%”                                 - the string "+_×:%"
       Œ!                               - all permutations
         ǀ                             - apply link (4) to each permutation

Bağlantılar bununla değerlendirilir (muhtemelen farklı bir yapıyla gelişebilirdim):

⁾[]i$€Ḥæ%3+\¬œp¹Ḋ€      (1) Helper link: Outputs a list of expressions within brackets, e.g. "[[[1]+[3]]]×[[[4]]]"↦"[[1]+[3]]","[[4]]"
⁾[]i$€Ḥæ%3                 - map "[" to 2, "]" to -2, and any other character to 0.
          +\¬              - cumulative sum negated: 1s at characters not in brackets (includes opening brackets), 0s otherwise (includes closing brackets)
             œp¹           - partition the input, not including borders, based on the sum to get "[[[1]+[3]]","[[[4]]"
                Ḋ€         - remove opening brackets
ǵḟØDO%9µÐṀṪɓœṣ⁹,ṚÑj@¥/ (2) Return the input to this link with one of the expressions from (1) evaluated
ǵVṾµ1ĿFḟØDḟ”-Lµ?ÐL     (3) link called from part 1: Evaluates expressions
 µ  µ          µ?          - if:
     1ĿFḟØDḟ”-L            - the input contains no operators within brackets:         
  VṾ                         - evaluate this one expression with normal Jelly calculation and return to string
                           - otherwise:
Ç                            - evaluate one subexpression using link (2)
                  ÐL       - repeat this until a single output is determined

Maksimum ve minimum arasındaki fark, link (5) deki kodla hesaplanır:

µṾL_L’ỊµÐfV€ṢIS (5b) determine difference between minimum and maximum
µ      µÐf        - filter out outputs involving division or modulo by 0. Determined with:
 ṾL_L’Ị           - actual numbers have their unevaled form Ṿ no more than one byte longer than the non-unevaled form.
          V€      - evaluate each of these valid numbers to get integers from strings
            Ṣ     - sort
             IS   - return the sum of all difference between consecutive elements.

4
Muhtemelen şimdiye kadar gördüğüm en uzun Jelly cevabı (gömülü veri olmadan). Aferin!
Keyu Gan

@KeyuGan Daha uzun Jelly cevapları istiyorsanız, bu cevaba bakın . Sıkıştırmadan başka uzun Jelly cevaplarını düşünemiyorum.
fireflame241

6

Python 2 , 235 234 233 226 bayt

Anders Kaseorg sayesinde -1 bayt (ve düzeltme) !

-7 Adım bay Adım sayesinde !

from itertools import*
def f(e,a=()):
 for o in permutations("+-*/%"):
	l=e[:]
	for c in o:
	 for i in range(len(l),0,-1):
		if l[i-1]==c:l[i-2:i+1]=["("+l[i-2]+l[i-1]+l[i]+")"]
	try:a+=eval(*l),
	except:0
 print max(a)-min(a)

Çevrimiçi deneyin!


1
İşlev gönderimleri yeniden kullanılabilir olmalıdır . Bu sorunu abir liste yerine demet bırakarak çözebilir ve hatta ( a=(), a+=eval(*l),) yaparak 1 bayt kaydedebilirsiniz .
Anders Kaseorg

Huh, TIL. Bahşiş için teşekkürler!
notjagan

1
Python 2’de olduğunuz için, girintiye yönelik boşluk ve sekmeleri değiştirerek bazı baytları kaydedebilirsiniz (bu durumda, 2 boşluk -> sekme, üç boşluk -> sekme + boşluk, dört boşluk -> iki sekme) Çevrimiçi deneyin!
Stephen,

4

Haskell 582 bayt

Bu neredeyse umduğum gibi gitmedi ...

import Data.List
f x=case x of '+'->(+);'-'->(-);'*'->(*);'/'->div;_->rem
e _ s[]=s
e 1 s(')':x:a)|0<-(read$e 0""a),(x=='%'||x=='/')=""|""<-(e 0""s)=""|""<-(e 0""a)=""|0<3=show$(f x)(read$e 0""s)$read$e 0""a
e 1 s")"=e 0""s
e n s(')':a)=e(n-1)(s++")")a
e 0 s('(':a)=e 1 s a
e n s('(':a)=e(n+1)(s++"(")a
e n s(x:a)=e n(s++[x])a
n?s=take n$cycle s
a!b=e 0""(9?"("++(concat$zipWith(++)a(b++[[]]))++9?")")
c#b|l<-[read x|x<-map(c!)(a b),x/=""]=maximum l-minimum l
a c=transpose$map(\x->map((\(Just q)->q).lookup x)$map(\a->zipWith(\x y->(y,x?")"++y:x?"("))[1..5]a)$permutations"+-*%/")c

Çevrimiçi Deneyin!

Uzun bir programda golf oynamaya çalışmak sadece kötü kod yazmamı sağlıyor :(

Anders'in algoritmasını Haskell'de kullanmaya çalıştım, ama kontrolüm dışında kaldı

E işlevi belirli bir değerlendirme durumu gibidir. (#), tamsayıları ve bir işleç dizesini temsil eden dizelerin bir listesini alır ve mümkün olan maksimum ve minimum değerler arasındaki farkı döndürür. Örneğin

(#) ["9","8","1","4"] "*+-" => 32

1
Eğer yeniden adlandırdıysanız #için ##, yeniden adlandırmak olabilir eiçin (#): şöyle,(n#s)(x:a)=...
Esolanging Meyve

Aşağıdaki üç sık kullanılan işlevi takma iselerseniz, 6 bayt daha kaydedebilirsiniz. r=read;j=zipWith;o=mapve sonra bu işlevleri harf takma adları ile değiştirin.
maple_shaft

Ayrıca 592 byte, 582
saymıyorum.

3

Pyth, 45 bayt

KS.nm.x.vj\ u.nm+*H/kHckHGd]s.iFQY.p_{eQ-eKhK

Daha fazla optimizasyon yapılabileceğinden eminim, ama şimdiye kadar hoşuma gitti.

Böyle girişi Alır: [9, 8, 1, 4], ["*", "+", "-"].

Çevrimiçi deneyin!


2
Bir açıklama ekleyebilir misiniz?
Jim,

2

Mathematica, 186 164 159 bayt

eMax@#-Min@#&[Fold[#//.{m___,x_,#2[[0]],y_,n___}:>{m,x~Last@#2~y,n}&,e,#]&/@Permutations@{"+"@Plus,"-"[#-#2&],"*"@Times,"/"@Quotient,"%"@Mod}/. 0/0|1/0->{}]

\[Function] 3 bayt alır.

Bazı alternatifler (sayıları aynı tutar)

#2-#&@MinMax[...] değiştirmek Max@#-Min@#&[...]

Head@#2 değiştirmek #2[[0]]

Online Deneyin http://sandbox.open.wolframcloud.com : girmek ( .... )[{60, "/", 8, "%", 8, "*", 6, "%", 4, "*", 5}]ile ....test durumu için yukarıdaki kodu ile değiştirilir 60 / 8 % 8 * 6 % 4 * 5. Değerlendirmek için basın Shift + enter.


2

Javascript, 280 bayt

Not : Tam sayı bölümü, kat işlevini kullanarak yuvarlanır; bu, negatif sayılar sıfırdan uzağa yuvarlanır anlamına gelir.

Bu çözüm bu cevaba dayanmaktadır .

b=>(Math.max(...(f=(a,h="(",i=")",r=[...a[d="replace"](/[^-+*/%]|(.)(?=.*\1)/g,"")])=>(r[0]?(r.map((c,j)=>s=s.concat(f(h+a[d](RegExp("\\"+(n=r.concat()).splice(j,1),"g"),i+c+h)+i,h+"(",i+")",n)),s=[]),s):(a=eval(`(${a})`[d](/\(/g,"Math.floor(")))==a&&1/a?a:r))(b))-Math.min(...f(b)))

Örnek kod pasajı:

g=

b=>(Math.max(...(f=(a,h="(",i=")",r=[...a[d="replace"](/[^-+*/%]|(.)(?=.*\1)/g,"")])=>(r[0]?(r.map((c,j)=>s=s.concat(f(h+a[d](RegExp("\\"+(n=r.concat()).splice(j,1),"g"),i+c+h)+i,h+"(",i+")",n)),s=[]),s):(a=eval(`(${a})`[d](/\(/g,"Math.floor(")))==a&&1/a?a:r))(b))-Math.min(...f(b)))

for(k=0;k<5;k++)
  v=["9*8+1-4","1+3*4","1+1","8-6+1*0","60/8%8*6%4*5"][k],
  console.log(`g(${v}) = ${g(v)}`)


A / b kasasını a / b | 0 ile değiştirerek uyumlu hale getirmek ne kadar zor olurdu?
trlkly

@ trlkly a/b|0, divide / modulo 0 hata kontrolünü durdurdu ancak Math.floor(a/b)çalıştı
Herman L

2

Haskell , 254 bayt

import Data.List.Split
import Data.List
f s=(-)<$>maximum<*>minimum$permutations(zip"+-*/%"[p(+),p(-),p(*),c$div,c$mod])>>=(s!)
p=((pure.).)
c o a b=[o a b|b/=0]
s![]=[read s]
s!((x,o):y)=case splitOn[x]s>>=(!y)of[]->[];l->l?o
[a]?_=[a]
(a:b)?o=b?o>>=o a

Çevrimiçi deneyin!

Giriş, 4 + 5 * 2 gibi tam bir dizedir. İşlemlerin tüm izinlerini oluşturur ve her izin için dizeyi yinelemeli olarak böler. Monad listesi ile bölümleri 0'a göre filtreler.


(%)modül operatörüdür. Sol argüman ve sağ argüman arasındaki bölünme işleminin geri kalanıdır.
maple_shaft

1

Piton 2 , 262 , 256 254 bayt

from itertools import*
def r(s,o):
 try:
  while o in s:i=s.index(o)-1;s[i:i+3]=[`eval(''.join(s[i:i+3]))`]
  return s
 except:0
def f(s):
 u=[int(v[0])for v in [reduce(r,O,s.split(' '))for O in permutations('*/%+-')]if v!=None];return abs(max(u)-min(u))

Çevrimiçi deneyin!


Sekmeleri kullanarak da bazı baytları kaydedin: Çevrimiçi deneyin!
Stephen,

1
Değiştirerek bir bayt kaydet in [için in[(boşluk gerekli değildir)
Zachary

1

PHP , 316 bayt

<?for(;$t++<54322;)count_chars($t,3)!=12345?:$p[]=$t;foreach($p as$x){for(list($z,$q)=$_GET,$b=1,$i=0;$y=strtr($x,12345,"/%*+-")[$i++];)while(-1<$k=array_flip($q)[$y]){$n=$k+1;if($b&=$z[$n]||ord($y)%10<6)eval("\$z[$k]=$z[$k]$y$z[$n]^0;");($s=array_splice)($z,$n,1);$s($q,$k,1);}$b?$r[]=$z[0]:0;}echo max($r)-min($r);

Çevrimiçi deneyin!

Expanded
for(;$t++<54322;)
  count_chars($t,3)!=12345?:$p[]=$t;
foreach($p as$x){
  for(list($z,$q)=$_GET,$b=1,$i=0;$y=strtr($x,12345,"/%*+-")[$i++];)
    while(-1<$k=array_flip($q)[$y]){
      $n=$k+1;
      if($b&=$z[$n]||ord($y)%10<6)
        eval("\$z[$k]=$z[$k]$y$z[$n]^0;");
      ($s=array_splice)($z,$n,1);
      $s($q,$k,1);
    }
  $b?$r[]=$z[0]:0;
}
echo max($r)-min($r);

Lase davası
63'tür

0

Python 3 , 284 bayt

Düzenleme: son örneği değerlendirirken bir sorun var gibi gözüküyor. Onu yarın inceleyeceğim.

Başka bir Python cevabı. Diğer herkes öfkelenemedi, ama buna dayanmamak için çok fazla zaman harcadım.

from itertools import*
def f(n,o):
 z=[]
 for p in permutations("+-*/%"):
  try:
   p,x,a=[*p],n[:],o[:]
   while(p):
    for i,d in enumerate(a):
     if d==p[0]:x[i+1]=str(eval(x[i]+d+x[i+1]));x.pop(i);a.pop(i)
    p.pop(0)
   z+=x
  except:0
 z=[*map(float,z)];return max(z)-min(z)

Çevrimiçi deneyin!


1
while(p)while pKaydedilen bir bayt için olabilir .
Zacharý

0

Clojure (+ kombinasyon), 342 377 + 41 = 418 bayt

Bir hata nedeniyle +35 bayt.

(fn[x y](let[l filter s first z #(l(fn[y]y)%)r(sort(z(for[e(q/permutations[+ - * quot mod])](try(loop[t e m y a x](if(=[]t)(s a)(let[j(s t)i(reverse(keep-indexed #(if(= j %2)%)m))](recur(rest t)(l #(not= j %)m)(loop[d 0 h a](if(=(count i)d)h(let[c(nth i d)f(inc c)](recur(inc d)(vec(z(assoc h c(j(nth h c)(nth h f))f nil)))))))))))(catch Exception _ nil)))))](-(last r)(s r))))

Çevrimiçi deneyin!

Bu işlevin çalışması useiçin clojure.math.combinatoricskütüphaneye (41 bayt):

(use '[clojure.math.combinatorics :as q])

Küçük farklar:

Bu işlev anonim bir işlevdir; bu işlemi kullanmak için yapmanız gereken anlamına gelir:

((fn[x y]...) numbers operators)

Ayrıca, quotyerine kelimesini kullanıyorum /(çünkü Clojure varsayılan olarak kesir bölme yapar) ve modyerine %.

Ungolfed programı:

(defn precedence [numbers operators]
  (let [results
        (sort
          (for [permute (c/permutations [+ - * / mod])]
            (loop [p-temp permute
                  o-temp operators
                  n-temp numbers]
              (if (empty? o-temp) (first n-temp)
                (let [first-p (first p-temp)
                      indices (reverse (keep-indexed #(when (= first-p %2) %) o-temp))]
                  (recur
                    (rest p-temp)
                    (filter #(not= first-p %) o-temp)
                    (loop [ind 0
                          n-through n-temp]
                      (if (= ind (count indices)) n-through
                        (let [current-ind (nth indices ind)]
                          (recur
                            (inc ind)
                            (vec
                              (filter #(not (nil? %))
                                (assoc n-through
                                  current-ind (first-p (nth n-through current-ind) (nth n-through (inc current-ind)))
                                  (inc current-ind) nil)))))))))))))]
    (- (last results) (first results))))

Bence sadece "Closure + Combinatorics" diyebilirsin ve useifadeyi puanlamak zorunda değilsin .
Esolanging Fruit,

@ Challenger5 Açıklamayı daha iyi yazacağınıza inanıyorum, çünkü varsayılan olarak, The characters used to import the library will likely be counted codegolf.meta.stackexchange.com/questions/10225/…
Keyu Gan

@KeyuGan Haklısın - Meta fikir birliğini yanlış anladım. Bence requireihtiyaçları için dahil kodunda ve uzunluğu bayt sayısına eklenir edilmelidir.
Esolanging Fruit,

@ Challenger5 Bu yüzden bytecount'uma 41 bayt eklemem gerekiyor, değil mi? TAMAM.
Qwerp-Derp

@ Qwerp-Derp Evet, ancak içe aktarma kodunuzun bir parçasıdır ve golf oynatabilirsiniz.
Esolanging Fruit,

0

JavaScript (ES6), 210 bayt

Sayı ve operatör dizisi olarak giriş

k=>(m=n=-k,r=(o,k,j=0)=>{for(o||(m=m>k?m:k,n=n<k?n:k);q=o[j++];(q>'%'&q<'/'||z)&&r(o.slice(0,j-1)+o.slice(j),h))for(h=[...k],z=1;i=h.indexOf(q)+1;h.splice(i-2,3,eval(a=h[i-2]+q+h[i])|0))z*=h[i]})('+-*/%',k)|m-n

Daha az golf oynadı

k=>(
  m = n = NaN,
  r =(o, k, j=0) => {
    // try all operators in o
    for(;q = o[j]; j++)
    {  
      // q : current operator, 
      // look for q inside the expression to evaluate
      for(h = [...k], z = 1; i = h.indexOf(q) + 1;)
      {
        a = h[i - 2]
        b = h[i]
        z *= b // trace if any second operand is zero
        // subst subexpression with its value
        h.splice(i - 2, 3, eval(a + q + b) | 0)
      }
      // now all subexp involving current operator are evaluated
      // the result is ok if current operator is not % or /
      //  OR if no second operand was zero
      (q > '%' & q < '/' || z) && 
        // try again recursively
        // using the remaining operators and the remaining expression
        r(o.slice(0, j) + o.slice(j+1), h) 
    }
    // if no more operators to try, check max and min
    // k is an array with 1 element, can be used like a single number
    o || (
      m = m > k ? m : k, 
      n = n < k ? n : k
    )
  },
  r('+-*/%', k),
  m-n
)

Ölçek

var F=
k=>(m=n=-k,r=(o,k,j=0)=>{for(o||(m=m>k?m:k,n=n<k?n:k);q=o[j++];(q>'%'&q<'/'||z)&&r(o.slice(0,j-1)+o.slice(j),h))for(h=[...k],z=1;i=h.indexOf(q)+1;h.splice(i-2,3,eval(a=h[i-2]+q+h[i])|0))z*=h[i]})('+-*/%',k)|m-n

function update() {
  var input = I.value.match(/\d+|\S/g)
  var result = F(input)
  O.textContent = I.value + ' -> ' + result + ' (max:'+m+' min:'+n+')'
}

update()
<input id=I value="60 / 8 % 8 * 6 % 4 * 5" oninput='update()'>
<pre id=O></pre>

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.