¡Dime cuántos problemas matemáticos tengo que hacer!

36

Mi maestra siempre me da el conjunto de problemas matemáticos más complicado para la tarea. Al igual que: pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even. Y quiero saber de antemano cuánto tiempo reservar para mi tarea, pero no quiero tener que resolver todo eso. Por eso es tu tarea programarlo para mí.

Presupuesto

  • Obtendrá una cadena que detalla los problemas que tengo que completar como args, stdio, etc.
  • Estarán separados por comas (posiblemente comma-spaceseparados)
  • Incluirá problemas individuales en forma de solo un número (por ejemplo 79)
  • Y rangos en la forma 17-18(de nuevo, tienes que lidiar con espacios opcionales)
  • Los rangos incluyen ambos extremos.
  • Los rangos estarán opcionalmente con el sufijo oddo even, que debe tener en cuenta.
  • Un conjunto de rangos / páginas estará antepuesto por un número de página en el formulario pg. 545:, nuevamente teniendo que ocuparse de espacios opcionales. Puede ignorarlos con seguridad, ya que necesita solucionar los problemas en todas las páginas
  • El texto puede estar en mayúsculas o minúsculas, pero no será en ambos.
  • Devuelve, stdout, etc. la cantidad de problemas que tengo que hacer para la tarea.
  • Como se trata de , ¡el código más corto en bytes gana!

Casos de prueba

pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even   ->    27
pg. 34: 1                                                    ->    1
PG. 565: 2-5,PG.345:7                                        ->    5
pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80                ->    70
pg.492: 2-4 odd,7-9 even                                     ->    2
Maltysen
fuente
12
¿Puede el profesor darle una gama de 2-4 odd? Parece causar algunos problemas para enfoques más simples.
Björn Lindqvist
1
^ Creo que este debería ser un caso de prueba, de acuerdo con el enunciado del problema actual.
mbomb007
2
Debería haber este caso de prueba:pg.492: 2-4 odd,7-9 even -> 2
mbomb007
2
¿Se pueden superponer los rangos? Por ejemplo 22-26,25-30?
Reto Koradi
1
@RetoKoradi no.
Maltysen

Respuestas:

15

CJam, 61 58 51 48 46 43 41 38 bytes

leuS-',/{':/W>:~_2*2<~z),>1f&\,5--~}%,

Verifique los casos de prueba en el intérprete de CJam .

Cómo funciona

leuS-      e# Read a line from STDIN, convert to uppercase and remove spaces.
',/        e# Split at commas.
{          e# For each chunk:
  ':/W>    e#   Split at colons and only keep the last chunk.
  :~       e#   Evaluate the string inside the array.
  _2*      e#   Copy the array, repeated twice.
  2<       e#   Keep only the first two elements.

           e#   In all possible cases, the array now contains exactly two
           e#   integers, which are equal in case of a single problem.

  ~        e#   Dump the array on the stack.
  z),      e#   Push [0 ... -N], where N is the second integer.
  >        e#   Discard the first M elements, where M is the first integer.
  1f&      e#   Replace each element by its parity.
  \,       e#   Push L, the length of the original array.

           e#   EVEN and ODD all push elements, so L is 1 for single problems,
           e#   2 for simple ranges, 5 for odd ranges and 6 for even ranges.

  5--      e#   Discard all elements equal to L - 5 from the array of parities.

           e#   This removes 0's for odd ranges, 1's for even ranges, -3's for
           e#   other ranges and -4's for single problems, thus counting only
           e#   problems of the desired parities.

  ~        e#   Dump the resulting array on the stack.
}%         e# Collect the results in an array.
,          e# Compute its length.
Dennis
fuente
¿Funciona esto con el último caso de prueba?
mbomb007
Lo hace. He agregado el último caso de prueba al enlace.
Dennis
10

Perl - 47 bytes

#!perl -p054
{map$\+=($_%2x9^lc$')!~T,$&..$'*/\d+ ?-/}}{

Modificado para pasar el nuevo caso de prueba.


Original

Perl - 36 bytes

#!perl -p054
$\+=/\d+ ?-/*($'-$&>>/o|e/i)+1}{

Contando el shebang como 4, la entrada se toma de stdin.


Uso de muestra

$ echo pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even | perl math-problems.pl
27

$ echo pg. 34: 1 | perl math-problems.pl
1

$ echo PG. 565: 2-5,PG.345:7 | perl math-problems.pl
5

$ echo pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80 | perl math-problems.pl
70

Advertencias

Para rangos pares / impares, se espera que al menos uno de los puntos finales coincida con la paridad del rango. Por ejemplo, 11-19 odd, 11-20 odd, y 10-19 oddtodos serán contados correctamente como 5, pero 10-20 oddserán contados sobre-como 6.

primo
fuente
¿Cómo funciona esto pg. 20: 13-15 even? o pg. 20: 13-14 even?
No es que Charles
1
*es un personaje más corto que &&, lo que facilita la mejora:$\+=/\d+ ?-/*($'-$&>>/o|e/i)+1for@F}{
Grimmy
1
Hombre, esto es inteligente! A menos que me falte algo, deberías poder eliminarlo lc=~.
Dennis
1
Obtuve esa T^parte, pero de alguna manera extrañé eso lccambió el caso de $'. Prepending lca $'hubiera sido un poco más corto. Eso debería funcionar para cualquier enfoque: lc$'!~(T^lc$_%2)o($_%2x9^lc$')!~T
Dennis
1
@Dennis para la versión anterior, habría requerido paréntesis. !~Tes genial, gracias!
primo
6

Python 2, 259 253 249 239 bytes

Pruébalo aquí

Esto probablemente todavía se puede jugar más al golf.

Editar: se corrigió un error que causaba que el mío no funcionara 2-4 evencomo esperaba. Luego hizo un ajuste para esa solución. ¡Esa solución me ahorró cuatro bytes!

Editar: ahora usa input()y +2 bytes para las dos comillas con las que el usuario debe rodear la entrada.

import re
c=0
for x in re.sub(r'..\..*?:','',input()).replace(' ','').split(','):
 y=x.split('-')
 if len(y)<2:c+=1
 else:
    a,b=y[0],y[1];d=int(re.sub('[A-z]','',b))-int(a)+1
    if b[-1]>':':d=d/2+d%2*(int(a)%2==ord(b[-3])%2)
    c+=d
print c

Menos golf (con comentarios!: D):

Espero que estos comentarios ayuden un poco. Todavía no estoy muy seguro si le expliqué esa última línea compleja correctamente o no.

import re
def f(s):
    c=0
    l=re.sub(r'..\..*?:','',s).replace(' ','').split(',')   # remove pg #'s and split
    for x in l:
        y=x.split('-')
        if len(y)<2:                                # if not a range of numbers
            c+=1
        else:
            a,b=y[0],y[1]                           # first and second numbers in range
            d=int(re.sub('[A-z]','',b))-int(a)+1    # number of pages
            if b[-1]>':':                           # if last character is not a digit
                # half the range
                # plus 1 if odd # of pages, but only if first and last numbers in the range
                #       are the same parity
                # ord(b[-3])%2 is 0 for even (v), 1 for odd (o)
                d=d/2+(d%2)*(int(a)%2==ord(b[-3])%2)
            c+=d
    print c
mbomb007
fuente
2
Solo una pequeña cosa, ya que está usando Python 2, puede usar espacios y pestañas (1 byte cada uno) como sangrías diferentes.
Consejo
También descubrí que tenía el recuento incorrecto al principio. Copiar pestañas de los editores las convierte en espacios.
mbomb007
Puede guardar al menos 4 bytes haciendo s=raw_input()y quitando alguna sangría.
4

Pyth, 43 42 44 42 bytes

lsm-%R2}hKvMc-ecd\:G\-eK?}\ed}edGYc-rzZd\,

Pruébelo en línea: demostración o prueba de arnés

Creo que todavía puedo cortar uno o dos bytes.

Explicación

lsm-%R2}hKvMc-ecd\:G\-eK?}\ed}edGYc-rzZd\,  implicit: z = input string
                                    rzZ     convert z to lower-case
                                   -   d    remove all spaces from z
                                  c     \,  and split by ","
  m                                         map each part d to:
               cd\:                           split d by ":"
              e                               and only use the last part (removes page number)
             -     G                          remove all letters (removes odd/even)
            c       \-                        split by "-"
          vM                                  and evaluate all (one or two) numbers
         K                                    and store the result in K
       }hK            eK                      create the list [K[0], K[0]+1, ..., K[-1]]
    %R2                                       apply modulo 2 to each element
   -                                          and remove:
                         }\ed                   "e" in d (1 for in, 0 for not in)
                        ?    }edG               if d[-1] in "abcde...z" else
                                 Y              dummy value
 s                                            combine all the lists
l                                             print the length                                      
Jakube
fuente
¿Funciona esto con el último caso de prueba?
mbomb007
@ mbomb007: lo hace.
Dennis
3

JavaScript (consola de Spidermonkey) - 139

Es más fácil probar en la línea de comando.

for(r=/[:,] *(\d+)[- ]*(\d+)? *(o|e)?/gi,m=readline(z=0);f=r.exec(m);z+=!b||((p=b-a)%2||!c|a%2^/e/i.test(c))+p/(2-!c)|0)[,a,b,c]=f
print(z)

Sin golf:

// any number set after "pg:" or a comma
// \1 is FROM, \2 is TO, \3 is odd/even 
r=/[:,] *(\d+)[- ]*(\d+)? *(o|e)?/gi;
m=readline();
z=0; // this is the sum.
while(f=r.exec(m)){
    [,from,to,oddEven]=f;
    if(!to) {
        z++;
    } else {
        if((to-from)%2) {
            // if to and from are not the same parity, add 1
            z++;
        } else {
            // if to and from are not the same parity...
            if(!oddEven) {
                // and we don't have a parity marker, add one
                z++;
            } else if(a%2 != /e/i.test(c)) {
                // if we do have a parity marker,
                // AND the parity of from and to matches the 
                // parity of the oddEven sign, then add 1
                z++;
            }
        }
        // then add the difference between to-from and
        // if oddEven exists, divide by two and round down
        z+=(to-from)/(oddEven?2:1)|0;
    }

}
print(z);
No es que Charles
fuente
¿ [,from,to]Simplemente puede ser [from,to]?
Yytsi
1
@TuukkaX no porque es para descartar el primer valor de la matriz r.exec, que contiene toda la cadena coincidente.
Patrick Roberts
3

Factor - 488 bytes:

USING: arrays ascii kernel math math.parser math.ranges pcre sequences ;
IN: examples.golf.homework

: c ( a -- b )
    >lower "(?:[,:]|^) *(\\d+) *(?:- *(\\d+) *(e|o)?)?" findall [
        rest [ second dup string>number swap or ] map
        dup length 1 = [ drop 1 ] [
            dup length 2 = [ first2 swap - 1 + ] [
                first3 "o" = [ [a,b] [ odd? ] count ] [
                    [a,b] [ even? ] count
                ] if
            ] if
        ] if
    ] map sum ;
Björn Lindqvist
fuente
2

Bash 344 315 306 294 262 252 242 240

IFS=,
o(){ R=0;for ((i=$1;i<=$2;R+=i++%2));do :
done
}
e(){ q=$R;o $*;((R=q-R))
}
for c in ${1,,};do
c=${c#*:}
m=${c##* }
l=${c%-*}
l=${l// }
h=${c#*-}
[[ a< $m ]]&&h=${h% *}
h=${h// }
((R=h-l+1))
eval "${m::1} $l $h"
((t+=R))
done;echo $t

No creo que haya jugado al golf tanto como sea posible, pero no está mal para una primera presentación. Versión comentada a continuación.

IFS=, # Setup IFS for the for loops, We want to be able to split on commas

o(){ # Odd
    R=0  # Reset the R variable

    # Increments R for each odd element in the range
    # $1-$2 inclusive
    for ((i=$1;i<=$2;R+=i++%2));do
        : # Noop command
    done
}

e(){ # Even
    # Save R, it contains the total number of elements between low
    # and high
    q=$R
    # Call Odd, This will set R
    o $*
    # Set R = total number of elements in sequence - number of odd elements.
    ((R=q-R))
}

# This lowercases the firs arg. IFS causes it to split on commas.
for c in ${1,,};do
    c=${c#*:}  # Strips the page prefix if it exists
    m=${c##* }  # Capture the odd/even suffix if it exists
    l=${c%-*}  # Capture low end of a range, Strips hyphen and anything after it
    l=${l// }  # Strips spaces
    h=${c#*-}  # Capture high end of a range, Strips up to and including hyphen

    # If we have captured odd/even in m this will trigger and strip
    # it from the high range variable.
    [[ a< $m ]]&&h=${h% *}
    h=${h// }  # Strip Spaces

    # Give R a value.
    # If we are in a range it will be the number of elements in that range.
    # If we arent l and h will be equal are R will be 1
    ((R=h-l+1))

    # Call the odd or even functions if we captured one of them in m.
    # If we didnt m will contain a number and this will cause a warning
    # to stderr but it still works.
    eval "${m::1} $l $h"

    # Add R to total
    ((t+=R))
done

# Print result
echo $t

Ejecute los casos de prueba:

bash math.sh "pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even"
bash math.sh "pg. 34: 1"
bash math.sh "PG. 565: 2-5,PG.345:7"
bash math.sh "pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80"
bash math.sh "pg.492: 2-4 odd,7-9 even"

Dependiendo de cómo lea las reglas, podría ser posible guardar otros 4 bytes. Si par / impar siempre es minúscula ${1,,}se puede cambiar a$1

Daniel Wakefield
fuente
¿Funciona esto con el último caso de prueba?
mbomb007
Solo lo probé y sí, lo hace.
Daniel Wakefield
1

JavaScript ( ES6 ), 149

Ejecute el fragmento en Firefox para probar

F=s=>s.replace(/([-,.:]) *(\d+) *(o?)(e?)/ig,(_,c,v,o,e)=>
  c=='-'?(t+=1+(o?(v-(r|1))>>1:e?(v-(-~r&~1))>>1:v-r),r=0)
  :c!='.'&&(t+=!!r,r=v)
,r=t=0)&&t+!!r

// Less golfed

U=s=>{
  var r = 0, // value, maybe range start
  t = 0; // total
  s.replace(/([-,.:]) *(\d+) *(o?)(e?)/ig, // execute function for each match
    (_ // full match, not used
     , c // separator char, match -:,.
     , v // numeric value
     , o // match first letter of ODD if present
     , e // match first letter of EVEN if present
    )=>
    {
      if (c == '-') // range end
      {
        t++; // in general, count range values as end - start + 1
        if (o) // found 'odd'
        {
          r = r | 1; // if range start is even, increment to next odd
          t += (v-r)>>1; // end - start / 2
        }
        else if (e) // found 'even'
        {
          r = (r+1) & ~1; // if range start is odd, increment to next even
          t += (v-r)>>1; // end - start / 2
        }
        else
        {
          t += v-r; // end - start
        }
        r = 0; // range start value was used
      }
      else if (c != '.') // ignore page numbers starting with '.'
      { 
        // if a range start was already saved, then it was a single value, count it
        if (r != 0) ++t;
        r = v; // save value as it counld be a range start
      }
    }
  )            
  if (r != 0) ++t; // unused, pending range start, was a single value
  return t
}

// TEST

out=x=>O.innerHTML+=x+'\n';

test=["pg. 546: 17-19, 22, 26, pg. 548: 35-67 odd, 79, 80-86 even",
"pg. 34: 1", "PG. 565: 2-5,PG.345:7",
"pg. 343: 5,8,13 - 56 even,pg. 345: 34 - 78,80"];

test.forEach(t=>out(t + ' --> ' + F(t)))
<pre id=O></pre>

edc65
fuente
1

C ++ 226 224 222

Sé que llego un poco tarde a la fiesta, pero esto parecía un problema divertido y la falta de entradas que usaban lenguajes C-family me molestó.

Entonces, aquí hay una función de C ++ que no utiliza expresiones regulares o sustitución de cadenas, solo algunas matemáticas simples:

void f(){char c;int o=0,i,j;while(cin>>c)c=='p'||c==80?cin.ignore(9,58):cin.unget(),cin>>i>>c&&c==45?cin>>j>>c&&(c=='e'||c=='o')?cin.ignore(9,44),c=='e'?i+=i&1,j+=!(j&1):(i+=!(i&1),j+=j&1),o+=(j-i)/2:o+=j-i:0,++o;cout<<o;}

Sin golf :

void f()
{
  char c;
  int o=0,i,j;
  while(cin>>c)
    c=='p'||c==80?cin.ignore(9,58):cin.unget(),
    cin>>i>>c&&c==45?
      cin>>j>>c&&(c=='e'||c=='o')?
        cin.ignore(9,44),
        c=='e'?
          i+=i&1,j+=!(j&1)
        :(i+=!(i&1),j+=j&1),
        o+=(j-i)/2
      :o+=j-i
    :0,
    ++o;
  cout<<o;
}

No dije que sería legible, ¿verdad? :) Los operadores ternarios son un infierno. Sin embargo, hice mi mejor esfuerzo para (forma de) formatearlo, así que espero que ayude al menos un poco.

Uso :

#include <iostream>
using namespace std;

void f(){char c;int o=0,i,j;while(cin>>c)c=='p'||c==80?cin.ignore(9,58):cin.unget(),cin>>i>>c&&c==45?cin>>j>>c&&(c=='e'||c=='o')?cin.ignore(9,44),c=='e'?i+=i&1,j+=!(j&1):(i+=!(i&1),j+=j&1),o+=(j-i)/2:o+=j-i:0,++o;cout<<o;}

int main()
{
  f();
}
Alexander Revo
fuente
207 bytes
techo
0

Python 2 - 163 bytes:

Pruébalo aquí

La entrada debe ser entre comillas

import re
print len(eval(re.sub('([^,]+:|) *(\d+) *-? *(\d*)(?=.(.)).*?,',r'[x for x in range(\2,\3+1 if \3.0 else \2+1)if x%2!="oe".find("\4")]+',input()+',[]')))

Explicación:

El enfoque general es convertir la entrada existente en python válida, luego evaluar esto. Cada valor separado por comas se convierte en una matriz, que luego se agregan todas juntas y la longitud da el resultado final.

Por ejemplo, con la entrada 12-15 odd,19, antes de la evaluación, la sustitución de expresiones regulares producirá:

[x for x in range(12,15+1 if 15.0 else 12+1)if x%2!="oe".find("o")]
+[x for x in range(19,+1 if .0 else 19+1)if x%2!="oe".find("[")]
+[]

Para desglosar esto aún más:

  • 15+1 if 15.0 else 12+1 Este bit se asegurará de que el segundo argumento de range () sea correcto dependiendo de si hay un rango o un valor dado (si \ 3 está vacío, \ 3.0 se evaluará como falso).
  • if x%2!="oe".find("o")Dependiendo del valor que se encuentre a dos caracteres del último dígito en el rango ( (?=.(.))en la expresión regular - mirar hacia adelante dos caracteres sin consumirlos), hay tres resultados posibles:

    • x%2!="oe".find("o")evalúa a x % 2 != 0(solo coincidencia impar)
    • x%2!="oe".find("e")evalúa a x % 2 != 1(solo emparejado)
    • x%2!="oe".find("[")se evalúa en x % 2 != -1(este carácter podría ser varias cosas, ya que está a solo dos caracteres del último dígito, pero solo estará o o e si se pretende impar / par)
  • El + [] aparentemente aleatorio al final es para asegurar que el último token en la lista separada por comas tenga un carácter a dos del último dígito, pero también nos permite agregar algo al final para usar el último '+' que habría estado siguiendo de otra manera.
Jarmex
fuente