Jumlahkan durasi waktu

18

Tantangan

Tulis kode terpendek yang dapat menjumlahkan semua durasi waktu yang muncul di stdin. Program hanya harus mempertimbangkan string yang cocok dengan salah satu pola berikut dan abaikan sisanya.

    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)

contoh string yang cocok dengan pola yang disebutkan:

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

Outputnya harus dalam bentuk

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

Contoh

STDIN

Lihat video Selamat Datang.
Video: 10:37 menit.
Lihat pengantar video ke kursus.
Video: 3:30 mnt. Lihat video tentang cara menggunakan Ikhtisar Pelajaran.
Video: 9:13 mnt.
Lihat ikhtisar video tentang cara menggunakan sistem Epsilen untuk membagikan pekerjaan Anda.
Video: 03:15 mnt.
Lihat video untuk mempelajari tentang Penilaian Kesiapan Akademik (STAAR) Negara Bagian Texas.
Video: 1:05:26 mnt.

STDOUT

1 jam 32m 1d

Alfredo Diaz
sumber
Bagaimana dengan string 10:4:56? Menurut spesifikasi saat ini mereka harus diperlakukan sebagai 4m 56s, bagian 10akan diabaikan. Pertanyaan yang sama tentang 10:12:7apakah artinya 10m 12smengabaikan 7? Atau penanganan string seperti itu dapat didefinisikan implementasi?
Qwertiy
Program seharusnya hanya mempertimbangkan durasi waktu dengan zero-padding di bidang menit dan kedua. Dalam contoh Anda string "10: 4: 56" akan diperlakukan sebagai 4m 56s. Juga string "10: 12: 7" akan ditafsirkan sebagai 10m 12s.
Alfredo Diaz
Aneh, tapi ok :)
Qwertiy
Bagaimana Anda mendapatkan 1h 19m 18soutput? 37+30+13+15+26==121, 10+3+9+3+5==30, 1==1, Jadi saya berharap 1h 32m 01s. Apa yang salah dalam logika ini? Juga, format output seperti itu adalah yang diharapkan, bukan?
Qwertiy
Kamu benar. Maaf: S
Alfredo Diaz

Jawaban:

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

Cobalah online.

Ini membutuhkan input dari STDIN dengan cara yang sama seperti jawaban Javascript, seperti teks yang dikutip dengan baris baru sebagai \ns.

Sampel:

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

Keluaran

1h 32m 1s

Contoh bekerja dengan tanggal yang lebih aneh:

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

Keluaran

0h 11m 20s

(Hanya 10:10 dan 1:10 yang sah kali)

Alasan utama mengapa ini sangat lama adalah karena Pyth tidak akan membiarkan Anda mengekstrak kecocokan positif. Alih-alih, ini cocok dengan semua yang bukan waktu yang valid, dan menggantinya dengan karakter spasi. Kemudian, pemisahan di whitespace hanya menyisakan beberapa kali dan beberapa angka bandel. Angka yang berlebih dihapus dengan memeriksa :karakter, yang akan dihapus dari waktu yang tidak valid. Ini hampir bisa dipastikan golf lebih lanjut;)

FryAmTheEggman
sumber
Bajingan beruntung bahwa Pyth memiliki regex juga !
Pengoptimal
@Optimizer: D Itu benar-benar menyakitkan. Saya berpikir untuk menyarankan mengubah perilaku "cocok" untuk berubah berdasarkan arg yang Anda berikan (saat ini hanya memeriksa bahwa itu adalah non-string)
FryAmTheEggman
6

Javascript ES6, 138 karakter

Fungsi, 139

Mengambil string sebagai argumen dan menulis output ke konsol:

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

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

Uji fungsi

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

Keluaran

"1h 32m 1s"
Qwertiy
sumber
Baik. Bekerja dengan baik di Firefox Developer Edition 36.0a2, pemformatan gagal hanya di Firefox 34.0.
manatwork
Promt tidak mengizinkan string multiline. Tapi saya bisa menambahkan versi dengan prompt () memanggil dalam jumlah karakter yang sama :) Saya bahkan mempersingkat 1 simbol)))
Qwertiy
@Optimizer Bagaimana cara memasukkannya?
Qwertiy
@Optimizer Memasukkan baris baru tidak berfungsi di FF 35.0 saya.
Qwertiy
Saya tidak bisa membuatnya bekerja. Saya mencobanya di ideone.com ideone.com/56EHgV
Alfredo Diaz
4

JavaScript, ES6, 208 200 197 byte

Saya tahu ini super panjang, tapi saya ingin menjelajahi fitur terbaru ES6, membalikkan, mengurangi peta, fungsi panah dan pemahaman array (operator spread).

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

Jalankan cuplikannya di Firefox terbaru.

Bagaimana cara kerjanya (ungolfed sedikit)

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
)
Pengoptimal
sumber
4

Bash (dengan grep, sed, awk, dan date): 124 byte, 120 byte

Cukup kirimkan teks ke ini:

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

Bagaimana itu bekerja

  • grep: mengeluarkan string dari input yang hanya berisi 0123456789:
  • sed: mengubah MM: SS dan M: SS menjadi: M: SS
  • awk: menghitung detik, string kosong adalah 0
  • xargs: meneruskan input sebagai argumen saat ini
  • tanggal: mengonversi detik sejak zaman (diawali dengan @) ke format yang diperlukan
pgy
sumber
Bukankah jam ini terkait dengan zona waktu Anda?
Qwertiy
Anda benar, tangkapan yang bagus :) Menambahkan flag -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"

Itu terjadi pada algoritma yang sama dengan Optimizer (grep, split, reverse, add).

Saya bukan ahli Perl, jadi mungkin jumlah byte dapat dikurangi.

Tidak disatukan

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";
coredump
sumber
Sedangkan bagi saya, aneh melihat solusi perl lebih lama dari javascript satu :)
Qwertiy
Nah, jika bahkan shebang dihitung, itu normal menjadi lebih lama.
manatwork
@ Kuertiy, aku setuju. Harapan saya adalah bahwa beberapa guru Perl akan membantu saya memperbaikinya.
coredump
@manatwork Mengapa ini penting?
Qwertiy
@ Qwertiy, karena coredump lupa untuk mengeluarkannya dari hitungan. : S Bisa saja dihapus (bersama dengan semua mykata kunci itu).
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]

Tidak disatukan + beranotasi:

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 hadir dengan time!datatype sendiri . Anda dapat melihat bagaimana kode di atas memanfaatkan ini dari contoh di bawah ini (dari dalam konsol 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
sumber
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)

Saya tidak tahu cara mengompres lebih lanjut.

Tidak disatukan

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

Mathematica 300 karakter

Latihan kecil ini membutuhkan banyak kode, bahkan untuk Mathematica. Tentunya ada cara yang lebih efisien untuk melakukan ini.

Golf

Dengan asumsi bahwa input disimpan dalam 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 "}]

Cara kerjanya (menggunakan kode yang tidak disatukan):

1-Temukan waktu.

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

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


2-Break menjadi jam, menit, detik

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-Jumlahkan waktu. Objek waktu adalah waktu jam. Mengurangi satu objek waktu dari objek lain menghasilkan durasi, dalam hal ini 92,0167 menit. QuantityMagnitudemenjatuhkan satuan ukuran.

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

92.0167


4-Convert 92.0167 menit menjadi jam, menit, detik.

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

1 jam 32m 1d

DavidC
sumber
1

Perl, 146

Entri saya mencetak hasilnya dengan spasi tambahan - saya harap tidak apa-apa

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"

Jika kita dapat berasumsi bahwa hanya akan ada satu kali per baris input, kita dapat memotong 4 karakter:

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"

Ini bekerja dengan mengakumulasi total detik yang berlalu dan memformat nilai itu sesudahnya.

KJP
sumber