Priorité des opérateurs: dans quelle mesure puis-je me tromper?

65

Dis que j'ai une expression:

9 * 8 + 1 - 4

Cette expression peut être interprétée de six manières différentes, en fonction de la priorité de l'opérateur:

(((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 (- + *)

Supposons que je suis un développeur et que je n'aime pas mémoriser les tableaux de priorité, etc., alors je vais deviner.

Dans ce cas, la marge d'erreur la plus grande serait 45-77, soit une différence de 32. Cela signifie que mon estimation ne sera que de 32.

Le défi

Compte tenu d' une expression consistant en les nombres et +, -, *, /(division entière) et %, la sortie de différence absolue de la plus grande et la plus petite valeur possible pour cette expression, en fonction de la priorité des opérateurs.

Caractéristiques

  • L'expression en entrée ne contiendra pas de parenthèses et chaque opérateur est associatif à gauche.
  • L'expression d'entrée ne contiendra que des entiers non négatifs. Cependant, les sous-expressions peuvent donner des résultats négatifs (par exemple 1 - 4).
  • Vous pouvez prendre l'expression dans n'importe quel format raisonnable. Par exemple:
    • "9 * 8 + 1 - 4"
    • "9*8+1-4"
    • [9, "*", 8, "+", 1, "-", 4]
    • [9, 8, 1, 4], ["*", "+", "-"]
  • L'entrée contiendra au moins 1 et au plus 10 opérateurs.
  • Toute expression contenant une division ou un modulo par 0 doit être ignorée.
  • Vous pouvez supposer que modulo ne recevra pas d'opérandes négatifs.

Cas de test

9 * 8 + 1 - 4             32
1 + 3 * 4                  3
1 + 1                      0
8 - 6 + 1 * 0              8
60 / 8 % 8 * 6 % 4 * 5    63
Fruit d'esolanging
la source
1
@AndersKaseorg Il semble que vous considériez %avoir deux précédents différents dans votre deuxième exemple.
Esolanging Fruit
1
Trois des «six» sont identiques, de même que deux autres. Cela laisse trois cas réels, pas six.
user207421
3
comment %fonctionne l'opérateur sur les nombres négatifs? La voie comme C ou Python ou autre chose?
Tsh le
8
Juste en disant, vous n'avez pas à ajouter la partie "et je suis paresseux" à votre description. Il suffit de dire que vous êtes un développeur. :)
Gryphon - Réintégrez Monica
1
@tsh N'importe quel comportement. Fais ce que tu veux. Vous pouvez faire voler des démons de mon nez .
Esolanging Fruit

Réponses:

27

Python 2 , 171 156 octets

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)

Essayez-le en ligne!

Comment ça fonctionne

Nous entourons chaque opérateur avec un nombre différent de paires de parenthèses orientées vers l'extérieur pour simuler différentes priorités (de toutes les manières possibles) et encapsulons suffisamment de paires de parenthèses orientées vers l'intérieur autour de la chaîne entière pour obtenir une expression possible eval. Par exemple, avec

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

on a

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

Anders Kaseorg
la source
Vous pouvez économiser 2 octets en déplaçant l' orextérieur sumpour supprimer une couche de crochets: sum([...],[])or[eval(a)]au lieu desum([...]or[[eval(a)]],[])
Strigoides
@Strigoides Je pensais que ce n'était pas équivalent, parce que le sumpeut être vide sans son argument, mais c'est très bien parce que le evaldoit échouer dans ce cas. Merci.
Anders Kaseorg
8

Gelée , 126 octets

"Préséance d'opérateur? Parenthèses? Pah, qui a besoin de ça?" - les défis de l'utilisation de Jelly pour un défi de priorité d'opérateur.

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

Essayez-le en ligne!

L'entrée est considérée comme une chaîne, par exemple "1 + 2_3 × 4: 5% 6". La multiplication de note utilise "×" au lieu de "*", la division utilise ":" au lieu de "/" et la soustraction utilise "_" au lieu de "-".

Fonctionnement Le programme est divisé en trois parties: générer toutes les expressions de préséance d'opérateur différente, les évaluer et renvoyer la différence entre le maximum et le minimum.

Toutes les expressions sont générées avec le code:

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

Les liens sont évalués avec ceci (je pourrais probablement m'améliorer avec une structure différente):

⁾[]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

La différence entre le maximum et le minimum est calculée avec le code dans le lien (5):

µṾ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.
fireflame241
la source
4
Probablement la réponse Jelly la plus longue (sans données intégrées) que j'ai jamais vue. Bien joué!
Keyu Gan
@KeyuGan Si vous voulez plus de réponses Jelly, regardez cette réponse . Je ne peux penser à aucune autre réponse Jelly longue sans compression.
fireflame241
6

Python 2 , 235 234 233 226 octets

-1 octet (et un correctif) grâce à Anders Kaseorg !

-7 octets grâce à Step Hen !

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)

Essayez-le en ligne!

notjagan
la source
1
Les soumissions de fonction doivent être réutilisables . Vous pouvez résoudre ce problème en laissant aun tuple à la place d'une liste, et même économiser 1 octet en procédant de la sorte ( a=(), a+=eval(*l),).
Anders Kaseorg
Hein, TIL. Merci pour le conseil!
Notjagan
1
Puisque vous êtes dans Python 2, vous pouvez économiser des octets en alternant les espaces et les tabulations pour l'indentation (dans ce cas, 2 espaces -> tab, trois espaces -> tab + espace, quatre espaces -> deux tabs) Essayez-le en ligne!
Stephen
4

Haskell 582 octets

Cela ne s'est pas passé aussi bien que je l'espérais ...

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

Essayez-le en ligne!

Essayer de jouer au golf avec un programme long me fait simplement écrire un mauvais code :(

J'ai essayé d'utiliser l'algorithme d'Anders dans Haskell, mais il est sorti de mon contrôle

La fonction e est comme un cas spécifique d’éval. (#) prend une liste de chaînes représentant des nombres entiers et une chaîne d'opérateurs et renvoie la différence entre les valeurs maximales et minimales possibles. par exemple

(#) ["9","8","1","4"] "*+-" => 32
H.PWiz
la source
1
Si vous avez renommé #à ##, vous pouvez renommer eà (#), comme suit:(n#s)(x:a)=...
Esolanging fruits
Si vous aliasez les trois fonctions suivantes couramment utilisées, vous pouvez enregistrer 6 octets supplémentaires. r=read;j=zipWith;o=mappuis remplacez ces fonctions par les alias de lettres.
maple_shaft
De plus, je compte 594 octets, pas 582.
maple_shaft
3

Pyth, 45 octets

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

Je suis sûr que beaucoup d'optimisation peut être faite, mais j'aime bien jusqu'à présent.

Prend entrée comme ceci: [9, 8, 1, 4], ["*", "+", "-"].

Essayez-le en ligne!

Trébuchette
la source
2
Pouvez-vous ajouter une explication?
Jim
2

Mathematica, 186 164 159 octets

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] prend 3 octets.

Quelques alternatives (conserve le même nombre de fois)

#2-#&@MinMax[...] remplacer Max@#-Min@#&[...]

Head@#2 remplacer #2[[0]]

Essayez-le en ligne sur http://sandbox.open.wolframcloud.com : entrez ( .... )[{60, "/", 8, "%", 8, "*", 6, "%", 4, "*", 5}]avec le ....code remplacé par le code ci-dessus pour le scénario de test 60 / 8 % 8 * 6 % 4 * 5. Appuyez sur Shift + enterpour évaluer.

utilisateur202729
la source
2

Javascript, 280 octets

Remarque : La division entière arrondit à l'aide de la fonction floor, ce qui signifie que les nombres négatifs s'éloignent de zéro.

Cette solution est basée sur cette réponse .

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)))

Exemple d'extrait de code:

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)}`)

Herman L
la source
Dans quelle mesure serait-il difficile de le rendre conforme en remplaçant le cas a / b par un / b | 0?
trlkly
@trlkly a/b|0arrête la vérification d'erreur divide / modulo 0, mais a Math.floor(a/b)travaillé
Herman L
2

Haskell , 254 octets

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

Essayez-le en ligne!

L'entrée est une chaîne complète, telle que 4 + 5 * 2. Elle génère toutes les permutations d'opérations et, pour chaque permutation, scinde la chaîne de manière récursive. Il filtre les divisions par 0 avec la liste monad.

Bartavelle
la source
(%)est opérateur de module. C'est le reste d'une opération de division entre l'argument gauche et l'argument droit.
maple_shaft
1

Python 2 , 262 256 254 octets

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))

Essayez-le en ligne!

Chas Brown
la source
Économisez quelques octets en utilisant également des onglets: Essayez-le en ligne!
Stephen
1
Économisez un octet en changeant in [sur in[(l'espace n'est pas nécessaire)
Zacharý
1

PHP , 316 octets

<?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);

Essayez-le en ligne!

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);
Jörg Hülsermann
la source
Le cas de lase est de 63. Votre erreur est due à la différence de priorité
donnée à
0

Python 3 , 284 octets

Edit: il semble que quelque chose ne va pas dans l'évaluation du dernier exemple. Je vais y regarder demain.

Une autre réponse en Python. Je ne pouvais pas sur-golfer tous les autres, mais j'ai passé trop de temps sur ça pour ne pas le mettre en place.

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)

Essayez-le en ligne!

Wrymug
la source
1
while(p)peut devenir while ppour un octet enregistré.
Zacharý
0

Clojure (+ combinatoire), 342 377 + 41 = 418 octets

+35 octets à cause d'un bogue.

(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))))

Essayez-le en ligne!

Pour que cette fonction fonctionne, vous devez utiliser usela clojure.math.combinatoricsbibliothèque (41 octets):

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

Nuances:

Cette fonction est une fonction anonyme, ce qui signifie que vous devez le faire pour l'utiliser:

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

De plus, j'utilise le mot à la quotplace de /(puisque Clojure effectue la division de fraction par défaut) et à la modplace de %.

Programme non-golfé:

(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))))
clismique
la source
Je pense que vous pouvez simplement dire "Fermeture + Combinatoire" et ne pas avoir à marquer le point use.
Esolanging Fruit
@ Challenger5 Je crois que vous feriez mieux de l'écrire dans la description, car par défaut, The characters used to import the library will likely be counted codegolf.meta.stackexchange.com/questions/10225/…
Keyu Gan
@KeyuGan Vous avez raison - j'ai mal compris ce méta-consensus. Je pense que les requirebesoins doivent être inclus dans le code et que sa longueur doit être ajoutée au nombre d'octets.
Esolanging Fruit
@ Challenger5 Il me faut donc ajouter 41 octets dans mon compte, pas vrai? D'ACCORD.
clismique
@ Qwerp-Derp Oui, mais l'importation fait partie de votre code et vous pouvez la jouer au golf.
Esolanging Fruit
0

JavaScript (ES6), 210 octets

Entrée sous forme de tableau de nombres et d'opérateurs

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

Moins golfé

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
)

Tester

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>

edc65
la source