Summieren Sie die Zeitdauern

18

Herausforderung

Schreiben Sie den kürzesten Code, der alle Zeitdauern summieren kann, die im stdin erscheinen. Das Programm muss nur die Zeichenfolgen berücksichtigen, die mit einem der folgenden Muster übereinstimmen, und den Rest ignorieren.

    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)

Beispiele für Zeichenfolgen, die mit den aufgelisteten Mustern übereinstimmen:

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

Die Ausgabe sollte von der Form sein

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

Beispiel

STDIN

Sehen Sie sich das Begrüßungsvideo an.
Video: 10:37 min.
Sehen Sie sich die Video-Einführung zum Kurs an.
Video: 3:30 min. Sehen Sie sich das Video zur Verwendung der Lektionsübersicht an.
Video: 9:13 min.
In der Videoübersicht sehen Sie, wie Sie mit dem Epsilen-System Ihre Arbeit teilen können.
Video: 03:15 min.
Sehen Sie sich das Video an, um mehr über die Bewertung der akademischen Bereitschaft (STAAR) im US-Bundesstaat Texas zu erfahren.
Video: 1:05:26 min.

STDOUT

1h 32m 1s

Alfredo Diaz
quelle
Was ist mit Streichern 10:4:56? Entsprechend der aktuellen Spezifikation müssen sie als behandelt werden 4m 56s, Teile 10werden ignoriert. Gleiche Frage zu 10:12:7bedeutet es 10m 12sbeim Ignorieren von 7? Oder kann der Umgang mit solchen Strings implementierungsdefiniert werden?
Qwertiy
Das Programm sollte nur Zeitdauern mit Nullenauffüllung im Minuten- und Sekundenfeld berücksichtigen. In Ihrem Beispiel wird die Zeichenfolge "10: 4: 56" als 4m 56s behandelt. Auch der String "10: 12: 7" wird als 10m 12s interpretiert.
Alfredo Diaz
Seltsam, aber ok :)
Qwertiy
Wie bist du 1h 19m 18szur Ausgabe gekommen? 37+30+13+15+26==121, 10+3+9+3+5==30, 1==1, So erwarte ich 1h 32m 01s. Was ist falsch an dieser Logik? Ein solches Ausgabeformat ist auch dasjenige, das erwartet wird, nicht wahr?
Qwertiy
Du hast recht. Entschuldigung: S
Alfredo Diaz

Antworten:

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

Probieren Sie es online aus.

Dies erfordert die Eingabe von STDIN auf die gleiche Weise wie die Javascript-Antwort, da Text mit Zeilenumbrüchen in Anführungszeichen wie \ns steht.

Probe:

"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."

Ausgabe

1h 32m 1s

Beispiel für die Arbeit mit seltsamen Daten:

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

Ausgabe

0h 11m 20s

(Nur der 10:10 und der 1:10 sind legitime Zeiten)

Der Hauptgrund dafür, dass dies so lange dauert, ist, dass Sie mit Pyth keine positiven Übereinstimmungen extrahieren können. Dies entspricht stattdessen allem, was keine gültige Zeit ist, und ersetzt es durch ein Leerzeichen. Durch Aufteilen auf Leerzeichen bleiben dann nur Zeiten und einige unberechenbare Zahlen übrig. Die überschüssigen Zahlen werden entfernt, indem nach :Zeichen gesucht wird , die aus ungültigen Zeiten entfernt wurden. Das könnte mit ziemlicher Sicherheit noch weiter golfen werden;)

FryAmTheEggman
quelle
Glückspilz , dass Pyth hat regex zu !
Optimierer
@Optimizer: D Es war allerdings ein echter Schmerz. Ich denke darüber nach, das "is match" -Verhalten zu ändern, basierend auf dem Argument, das Sie ihm geben (derzeit wird nur überprüft, ob es sich um eine Nicht-Zeichenfolge handelt)
FryAmTheEggman
6

Javascript ES6, 138 Zeichen

Funktion, 139

Nimmt string als Argument und schreibt die Ausgabe in die Konsole:

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

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

Funktion testen

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

Ausgabe

"1h 32m 1s"
Qwertiy
quelle
Okay. Funktioniert einwandfrei in Firefox Developer Edition 36.0a2, die Formatierung schlägt nur in Firefox 34.0 fehl.
Handarbeit
Promt erlaubt keine mehrzeiligen Zeichenfolgen. Aber ich kann Version mit prompt () Call in der gleichen Anzahl von Zeichen hinzufügen :) Ich
kürze
@Optimizer Wie man sie eingibt?
Qwertiy
@Optimizer Das Einfügen einer neuen Zeile funktioniert in meinem FF 35.0 nicht.
Qwertiy
Ich kann es nicht zum Laufen bringen. Ich habe es auf ideone.com versucht ideone.com/56EHgV
Alfredo Diaz
4

JavaScript, ES6, 208 200 197 Bytes

Ich weiß, das ist super lang, aber ich wollte die neuesten Funktionen von ES6, Rückwärtsfahren, Kartenverkleinern, Pfeilfunktionen und Array-Verständnis (Spread-Operator) kennenlernen.

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

Führen Sie das Snippet einfach in einem aktuellen Firefox aus.

Wie es funktioniert (ein bisschen ungolfed)

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
)
Optimierer
quelle
4

Bash (mit grep, sed, awk und date): 124 Bytes, 120 Bytes

Leiten Sie den Text einfach so ein:

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

Wie es funktioniert

  • grep: gibt Zeichenfolgen nur aus der Eingabe aus, die enthält 0123456789:
  • sed: verwandelt MM: SS und M: SS in: M: SS
  • awk: berechnet die Sekunden, leere Zeichenfolge ist 0
  • xargs: Übergibt die Eingabe als Argument an date
  • Datum: Konvertiert Sekunden seit der Epoche (mit dem Präfix @) in das erforderliche Format
pgy
quelle
Hängt diese Stunde nicht mit Ihrer Zeitzone zusammen?
Qwertiy
Du hast recht, netter Fang :) Hinzugefügt -u Flagge.
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"

Es ist zufällig derselbe Algorithmus wie der des Optimierers (grep, split, reverse, add).

Ich bin kein Perl-Experte, daher kann die Anzahl der Bytes möglicherweise verringert werden.

Ungolfed

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";
Core-Dump
quelle
Ich
finde
Naja, wenn auch der Shebang gezählt wird, ist es normal länger zu sein.
manatwork
@Qwertiy Ich stimme zu. Ich hoffe, dass mir ein Perl-Guru dabei hilft, das zu beheben.
Coredump
@manatwork Warum zählt es?
Qwertiy
@Qwertiy, weil coredump vergessen hat, es von der Zählung auszuschließen. : S Konnte gerade entfernt werden (zusammen mit all diesen mySchlüsselwörtern).
Handarbeit
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]

Ungolfed + kommentiert:

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 wird mit einem eigenen time!Datentyp geliefert . Wie der obige Code dies nutzt, können Sie dem folgenden Beispiel (in der Rebol-Konsole) entnehmen:

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

Ich kann nicht herausfinden, wie ich es mehr komprimieren kann.

Ungolfed

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
quelle
1

Mathematica 300 Zeichen

Diese kleine Übung nahm selbst für Mathematica viel Code in Anspruch. Sicher gibt es effizientere Möglichkeiten, dies zu tun.

Golf gespielt

Unter der Annahme, dass die Eingabe in gespeichert ist 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 "}]

Wie es funktioniert (mit unGolfed Code):

1-Finde die Zeiten.

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

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


2-Break in Stunden, Minuten, Sekunden

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-Summiere die Zeiten. Zeitobjekte sind Uhrzeiten. Das Subtrahieren eines Zeitobjekts von einem anderen gibt eine Dauer zurück, in diesem Fall 92.0167 Minuten. QuantityMagnitudeLässt die Maßeinheit fallen.

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

92.0167


4-Konvertieren Sie 92.0167 Minuten in Stunden, Minuten, Sekunden.

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

1h 32m 1s

DavidC
quelle
1

Perl, 146

Mein Eintrag druckt die Ausgabe mit einem Leerzeichen nach - ich hoffe, das ist in Ordnung

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"

Wenn wir davon ausgehen können, dass es pro Eingabezeile nur ein Mal gibt, können wir 4 Zeichen trennen:

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"

Diese arbeiten, indem sie die insgesamt verstrichenen Sekunden aufsummieren und diesen Wert anschließend formatieren.

KJP
quelle