Suma las duraciones de tiempo

18

Desafío

Escriba el código más corto que pueda sumar todas las duraciones de tiempo que aparecen en el stdin. El programa solo debe considerar las cadenas que coinciden con uno de los siguientes patrones e ignorar el resto.

    HH:MM:SS     (it will be interpreted as HH hours, MM minutes and SS seconds)        
    H:MM:SS      (it will be interpreted as H hours, MM minutes and SS seconds)
    MM:SS        (it will be interpreted as MM minutes, SS seconds)
    M:SS         (it will be interpreted as M minutes, SS seconds)

Ejemplos de cadenas que coinciden con los patrones enumerados:

    12:00:01  
    2:03:22  
    00:53  
    9:13

El resultado debe ser de la forma

    HHh MMm SSs      (that means HH hours, MM minutes and SS seconds with non-zero-padding)

Ejemplo

STDIN

Vea el video de bienvenida.
Video: 10:37 min.
Vea el video de introducción al curso.
Video: 3:30 min. Vea el video de cómo usar la Descripción general de la lección.
Video: 9:13 min.
Vea la descripción general en video de cómo usar el sistema Epsilen para compartir su trabajo.
Video: 03:15 min.
Vea el video para conocer la Evaluación de preparación académica del estado de Texas (STAAR).
Video: 1:05:26 min.

STDOUT

1h 32m 1s

Alfredo Diaz
fuente
¿Qué pasa con las cuerdas 10:4:56? Según la especificación actual, deben tratarse como 4m 56sparte 10, se ignorará. La misma pregunta sobre 10:12:7¿qué significa 10m 12signorar 7? ¿O se puede definir la implementación del manejo de tales cadenas?
Qwertiy
El programa solo debe considerar duraciones de tiempo con relleno de cero en los campos de minutos y segundos. En su ejemplo, la cadena "10: 4: 56" se tratará como 4m 56s. También la cadena "10: 12: 7" se interpretará como 10m 12s.
Alfredo Díaz
Extraño, pero está bien :)
Qwertiy
¿Cómo llegaste 1h 19m 18sa la salida? 37+30+13+15+26==121, 10+3+9+3+5==30, 1==1, Por lo que espero 1h 32m 01s. ¿Qué hay de malo en esta lógica? Además, dicho formato de salida es el que se espera, ¿no?
Qwertiy
Tienes razón. Lo sentimos: S
Alfredo Díaz

Respuestas:

3

Pyth 105

K"smh"J"\D\D+|\d+:(?=\d:)|:\d\D"W:QJ1=Q:QJd;FN_msdCfn2lTm+*]0</k\:2msbck\:cQ)~k+d+hK_`%+NZ60=Z/N60=KtK;_k

Pruébalo en línea.

Esto requiere la entrada de STDIN de la misma manera que la respuesta de Javascript, como el texto citado con líneas nuevas como \ns.

Muestra:

"View the Welcome video.\nVideo: 10:37 min.\nView the video introduction to the course.\nVideo: 3:30 min. View the video of how to use the Lesson Overview.\nVideo: 9:13 min.\nView the video overview of how to use the Epsilen system to share your work.\nVideo: 03:15 min.\nView the video to learn about the State of Texas Assessment of Academic Readiness (STAAR).\nVideo: 1:05:26 min."

Salida

1h 32m 1s

Ejemplo de trabajo con fechas más extrañas:

"10:10:5 and 5:1:10 and 27 or 16: or 1:1:1 or 11:1\n"

Salida

0h 11m 20s

(Solo el 10:10 y el 1:10 son tiempos legítimos)

La razón principal por la que esto es tan largo es que Pyth no le permitirá extraer coincidencias positivas. En cambio, esto coincide con todo lo que no es un tiempo válido y lo reemplaza con un carácter de espacio. Luego, dividir en espacios en blanco deja solo tiempos y algunos números rebeldes. Los números sobrantes se eliminan al buscar :caracteres, que se habrán eliminado de tiempos no válidos. Esto casi con seguridad podría ser más golfizado;)

FryAmTheEggman
fuente
Afortunado bastardo que tiene Pyth expresiones regulares demasiado !
Optimizador
@Optimizer: D Sin embargo, fue un verdadero dolor. Estoy pensando en sugerir cambiar el comportamiento de "es una coincidencia" para cambiar según el argumento que le des (actualmente solo comprueba que no es una cadena)
FryAmTheEggman
6

Javascript ES6, 138 caracteres

Función, 139

Toma una cadena como argumento y escribe la salida en la consola:

f=s=>(r=0,s.replace(/(\d\d?):(\d\d)(:(\d\d))?/g,(m,a,b,x,c)=>r+=x?+c+b*60+a*3600:+b+a*60),console.log("%dh %dm %ds",r/3600,r%3600/60,r%60))

Programa 138

prompt(r=0).replace(/(\d\d?):(\d\d)(:(\d\d))?/g,(m,a,b,x,c)=>r+=x?+c+b*60+a*3600:+b+a*60),console.log("%dh %dm %ds",r/3600,r%3600/60,r%60)

Prueba de funcionamiento

f("View the Welcome video.\n\
Video: 10:37 min.\n\
View the video introduction to the course.\n\
Video: 3:30 min. View the video of how to use the Lesson Overview.\n\
Video: 9:13 min.\n\
View the video overview of how to use the Epsilen system to share your work.\n\
Video: 03:15 min.\n\
View the video to learn about the State of Texas Assessment of Academic Readiness (STAAR).\n\
Video: 1:05:26 min.")

Salida

"1h 32m 1s"
Qwertiy
fuente
Okay. Funciona bien en Firefox Developer Edition 36.0a2, el formateo falla solo en Firefox 34.0.
manatwork
Promt no permite cadenas multilínea. Pero puedo agregar la versión con prompt () call en el mismo número de caracteres :) Incluso
acorté
@Optimizer ¿Cómo ingresarlos?
Qwertiy
@Optimizer Insertar una nueva línea no funciona en mi FF 35.0.
Qwertiy
No puedo hacer que funcione. Lo probé en ideone.com ideone.com/56EHgV
Alfredo Díaz
4

JavaScript, ES6, 208 200 197 bytes

Sé que esto es muy largo, pero quería explorar las últimas características de ES6, reversa, reducción de mapas, funciones de flecha y comprensión de matriz (operador de propagación).

alert(prompt().match(/\d\d?:\d\d(:\d\d)?/g).map(x=>[...x.split(":").reverse(),z=0].slice(0,3)).reduce((a,b)=>b.map((y,i)=>+y+ +a[i])).map((x,i)=>(z=(t=x+z|0)/60,t%60+"smh"[i])).reverse().join(" "))

Simplemente ejecute el fragmento en una versión más reciente de Firefox.

Cómo funciona (un poco descuidado)

alert(                              // Alert the final result
  prompt()                          // Take the input via prompt
  .match(/\d\d?:\d\d(:\d\d)?/g)     // Match only correct time formats
  .map(                             // Map all matches using this method
    x=>[                            // Take each element as argument x
      ...x.split(":").reverse(),    // split x on ":" and reverse the array, then spread it
      z=0                           // put 0 as last element of return array
    ].slice(0,3)                    // Take only first 3 elements of the array
  ).reduce(                         // Reduce the result using this method
    (a,b)=>                         // Pairwise elements of the array
    b.map(                          // Map array b
      (y,i)=>~~y+~~a[i]             // Convert b[i] to b[i]+a[i]
    )                               // Now we have array like [SS, MM, HH]
  ).map(                            // Map these three values for carry over calculation
    (x,i)=>(
      t=x+z,                        // z contains carryover amount, add it to this value
      z=(t/60)|0,                   // Carryover is now floor(t/60)
      t%60+"smh"[i]                 // Remove overflow from t and add "s", "m" or "h"
    )                               // Now we have array like ["SSs", "MMm", "HHh"]
  ).reverse().join(" ")             // Reverse it and join by space
)
Optimizador
fuente
4

Bash (con grep, sed, awk y date): 124 bytes, 120 bytes

Simplemente canalice el texto en esto:

grep -o '[:0-9]*'|sed 's/^[^:]*:[^:]*$/:\0/'|awk -F: '{T+=3600*$1+60*$2+$3}END{print"@"T}'|xargs date +"%Hh %Mm %Ss" -ud

Cómo funciona

  • grep: genera cadenas de la entrada que solo contiene 0123456789:
  • sed: convierte MM: SS y M: SS en: M: SS
  • awk: calcula los segundos, la cadena vacía es 0
  • xargs: pasa la entrada como argumento hasta la fecha
  • fecha: convierte segundos desde la época (con el prefijo @) al formato requerido
pgy
fuente
¿Esta hora no está relacionada con su zona horaria?
Qwertiy
Tienes razón, buena captura :) Se agregó la bandera -u.
pgy
3

Perl - 228 201

use integer;$h=0,$m=0,$s=0;while(<>){if(/(\d+:){1,2}\d+/){@a=reverse(split(/:/,$&));push @a,(0)x(3-@a);$s+=@a[0];$m+=@a[1];$h+=@a[2];}}$m+=$s/60;$s=$s%60;$h+=$m/60;$m=$m%60;print $h."h ".$m."m ".$s."s"

Resulta ser el mismo algoritmo que el Optimizador (grep, split, reverse, add).

No soy un experto en Perl, por lo que tal vez se pueda reducir el recuento de bytes.

Sin golf

use integer;                              # will do integer division
$h=0,$m=0,$s=0;
while(<>){
    if(/(\d+:){1,2}\d+/) {                # extract date formats
        @a = reverse(split(/:/,$&));      # split by ":" and reverse
        push @a,(0)x(3-@a);               # pad with zeros (minutes and hours)
        $s+=@a[0];                        # sum seconds
        $m+=@a[1];                        # sum minutes
        $h+=@a[2];                        # sum hours
    }
}

# convert seconds as minutes    
$m += $s / 60;
$s = $s % 60;

# convert minutes as hours
$h += $m / 60;
$m = $m % 60;

print $h."h ".$m."m ".$s."s";
volcado de memoria
fuente
En cuanto a mí, es extraño ver una solución perl más larga que javascript one :)
Qwertiy
Bueno, incluso si se cuenta el shebang, es normal que sea más largo.
manatwork
@Qwertiy estoy de acuerdo. Mi esperanza es que algún gurú de Perl me ayude a arreglar eso.
coredump
@manatwork ¿Por qué cuenta?
Qwertiy
@Qwertiy, porque coredump olvidó excluirlo del recuento. : S podría eliminarse (junto con todas esas mypalabras clave).
manatwork
3

Rebol - 174

n: charset"1234567890"a:[1 2 n]b:[":"2 n]c: 0 parse input[any[copy x[a b b](c: c + do x)| copy x[a b](c: c + do join"0:"x)| skip]]print reword"$1h $2m $3s"[1 c/1 2 c/2 3 c/3]

Sin golf + anotado:

n: charset "1234567890"                      ; setup \d regex equiv
a: [1 2 n]                                   ; parse rule for \d{1,2} 
b: [":" 2 n]                                 ; parse rule for :\d\d
c: 0                                         ; time counter

parse input [                                ; parse the input (STDIN)
                                             ; (no regex in Rebol)

  any [                                      ; match zero or more... 
                                             ;
      copy x [a b b] (c: c + do x)           ;  HH:MM:SS or H:MM:SS
                                             ;    - copy match to x
                                             ;    - increment time (c) by x
                                             ; OR
    | copy x [a b] (c: c + do join "0:" x)   ;  MM:SS or M:SS
                                             ;    - copy match to x
                                             ;    - "MM:SS" into "0:MM:SS" (join)
                                             ;    - then increment time (c)
                                             ; OR
    | skip                                   ;   no match so move through input
  ]
]

print reword "$1h $2m $3s" [1 c/1 2 c/2 3 c/3]

Rebol viene con su propio time!tipo de datos. Puede ver cómo el código anterior hace uso de esto en el ejemplo a continuación (desde dentro de la consola Rebol):

>> 0:10:37 + 0:3:30 + 0:9:13 + 0:3:15 + 1:05:26
== 1:32:01

;; Rebol would treat 10:37 as 10 hours & 37 minutes (and not MM:SS)
;; So we have to prefix the "0:"

>> join "0:" 10:37
== "0:10:37"

;; This is a string so we use Rebol DO evaluator to convert to time!

>> do join "0:" 10:37 
== 0:10:37

>> type? do join "0:" 10:37
== time!

>> hms: do join "0:" 10:37
== 0:10:37

>> hms/hour
== 0

>> hms/second
== 37

>> hms/minute
== 10
draegtun
fuente
2

Groovy - 195

M=60
r=(System.in.text=~/((\d?\d):)?(\d\d):(\d\d)/).collect{it[2..4]*.toInteger().inject{s,i->(s?:0)*M+i}}.inject{s,i->s+=i}
f=[];(2..0).each{j=M**it;s=r%j;f<<(r-s)/j;r=s}
printf("%sh %sm %ss",f)

No puedo entender cómo comprimirlo más.

Sin golf

M=60
r=(System.in.text=~/((\d?\d):)?(\d\d):(\d\d)/).collect{  // extract dates
    it[2..4]*.toInteger().inject{ s,i ->                 // convert to seconds
        (s?:0)*M+i
    }
}.inject{s,i ->
    s+=i                                                 // sum seconds
}

f=[];
(2..0).each{                                             // convert to h,m,s
    j=M**it;
    s=r%j;
    f<<(r-s)/j;
    r=s
}

printf("%sh %sm %ss",f)
Alfredo Diaz
fuente
1

Mathematica 300 caracteres

Este pequeño ejercicio tomó mucho código, incluso para Mathematica. Seguramente hay formas más eficientes de hacer esto.

Golfed

Suponiendo que la entrada se almacena en txt,

n=NumberString;
t=ToExpression;
o=TimeObject;

QuotientRemainder[QuantityMagnitude[Plus@@((o[#]-o[{0,0,0}])&/@
(StringSplit[StringCases[w,{(n~~":"~~n~~":"~~n),(n~~":"~~n)}],":"]
/.{{a_,b_}:> {0,t@a,t@b},{a_,b_,c_}:> {t@a,t@b,t@c}}))],60]/.{h_,m_}:> 
Row[{h,"h ",IntegerPart@m,"m ",Round[60 FractionalPart[m]],"s "}]

Cómo funciona (usando código no protegido):

1-Encuentra los tiempos.

StringCases[txt,{(NumberString~~":"~~NumberString~~":"~~NumberString),
(NumberString~~":"~~NumberString)}];

{"10:37", "3:30", "9:13", "03:15", "1:05:26"}


2-Break en horas, minutos, segundos

StringSplit[%,":"]/.{{a_,b_}:> {0,ToExpression@a,ToExpression@b},{a_,b_,c_}:> 
{ToExpression@a,ToExpression@b,ToExpression@c}}

{{0, 10, 37}, {0, 3, 30}, {0, 9, 13}, {0, 3, 15}, {1, 5, 26}}


3-Suma los tiempos. Los objetos de tiempo son tiempos de reloj. Restar un objeto de tiempo de otro devuelve una duración, en este caso 92.0167 minutos. QuantityMagnitudedeja caer la unidad de medida.

q=QuantityMagnitude[Plus@@((TimeObject[#]-TimeObject[{0,0,0}])&/@%)]

92.0167


4-Convertir 92.0167 minutos en horas, minutos, segundos.

QuotientRemainder[q,60]/.{h_,m_}:> Row[{h,"h ",IntegerPart@m,"m ",
Round[60 FractionalPart[m]],"s "}]

1h 32m 1s

DavidC
fuente
1

Perl, 146

Mi entrada imprime la salida con un espacio final, espero que esté bien

while(<>){for(/(\d?\d(?::\d\d){1,2})/g){$m=1;for(reverse split/:/,$_){$t+=$m*$_;$m*=60}}}for('s','m'){$o=($t%60)."$_ $o";$t/=60}print int$t,"h $o"

Si podemos suponer que solo habrá una vez por línea de entrada, podemos cortar 4 caracteres:

while(<>){if(/(\d?\d(:\d\d){1,2})/){$m=1;for(reverse split/:/,$&){$t+=$m*$_;$m*=60}}}for('s','m'){$o=($t%60)."$_ $o";$t/=60}print int$t,"h $o"

Estos funcionan acumulando el total de segundos transcurridos y formateando ese valor después.

KJP
fuente