求和持续时间


18

挑战

编写最短的代码,可以对标准输入中出现的所有持续时间求和。程序必须仅考虑与以下模式之一匹配的字符串,而忽略其余模式。

    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)

与枚举模式匹配的字符串示例:

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

输出应为以下形式

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

标准输入

观看欢迎视频。
视频:10:3​​7分钟。
观看该课程的视频介绍。
视频:3:30分钟。观看有关如何使用课程概述的视频。
视频:9:13分钟。
观看有关如何使用Epsilen系统共享您的工作的视频概述。
视频:03:15分钟。
观看视频以了解德克萨斯州学业准备状况评估(STAAR)。
视频:1:05:26分钟。

标准输出

1h 32m 1s


字符串怎么样10:4:56?根据当前规范,必须将它们视为4m 56s,部分10将被忽略。关于忽略10:12:7它意味着同样的问题吗?还是可以定义实现来处理此类字符串?10m 12s7
Qwertiy 2014年

程序只应在分钟和秒字段中考虑填充为零的持续时间。在您的示例中,字符串“ 10:4:56”将被视为4m 56s。字符串“ 10:12:7”也将被解释为10m 12s。
Alfredo Diaz 2014年

奇怪,但还可以:)
Qwertiy 2014年

您是如何获得1h 19m 18s输出的?37+30+13+15+26==12110+3+9+3+5==301==1,所以我希望1h 32m 01s。这个逻辑有什么问题?同样,这种输出格式是所期望的,不是吗?
Qwertiy 2014年

你是对的。抱歉:S
Alfredo Diaz 2014年

Answers:


3

腐霉菌 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

在线尝试。

这要求STDIN的输入方式与Javascript答案相同,如带引号的带有\ns的引号文本。

样品:

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

输出量

1h 32m 1s

使用怪异日期的示例:

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

输出量

0h 11m 20s

(只有10:10和1:10是合法时间)

这么长的主要原因是Pyth不允许您提取正匹配项。相反,它将匹配所有无效时间,并将其替换为空格字符。然后,在空白处分割仅留下时间和一些任性的数字。通过检查:字符将删除多余的数字,这些字符将从无效时间中删除。这几乎肯定可以进一步打下去;)


幸运的混蛋那Pyth具有正则表达式
Optimizer

@Optimizer:D虽然这确实是一个痛苦。我正在考虑建议根据您提供的arg更改“ is match”行为以进行更改(当前它仅检查它是否为非字符串)
FryAmTheEggman 2014年

6

Javascript ES6,138个字符

功能139

将字符串作为参数并将输出写入控制台:

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

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

测试功能

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

输出量

"1h 32m 1s"

好。在Firefox Developer Edition 36.0a2中工作正常,仅在Firefox 34.0中格式化失败。
manatwork 2014年

Promt不允许多行字符串。但我可以使用相同数量的chars来添加带有
alert

@Optimizer如何输入?
Qwertiy 2014年

@Optimizer在我的FF 35.0中无法插入新行。
Qwertiy 2014年

我无法正常工作。我在ideone.com ideone.com/56EHgV
Alfredo Diaz

4

JavaScript中,ES6,208个200 197字节

我知道这很长,但是我想探索一下ES6的最新功能,反向,映射减少,箭头功能和数组理解(扩展运算符)。

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

只需在最新的Firefox中运行该代码段即可。

工作原理(略微松懈)

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
)

4

Bash(带有grep,sed,awk和日期):124字节,120字节

只需将文本输入以下内容即可:

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

怎么运行的

  • grep:从仅包含输入的输出字符串 0123456789:
  • sed:将MM:SS和M:SS转换为:M:SS
  • awk:计算秒数,空字符串为0
  • xargs:将输入作为参数传递给日期
  • 日期:将自纪元(以@开头)以来的秒数转换为所需的格式

这个小时与您的时区无关吗?
Qwertiy 2014年

您说对了,不错:)添加了-u标志。
pgy 2014年

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"

它恰好与优化程序的算法相同(grep,split,reverse,add)。

我不是Perl专家,所以也许可以减少字节数。

不打高尔夫球

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

对于我来说,看到perl解决方案的时间长于javascript的时间是很奇怪的:)
Qwertiy 2014年

好吧,即使算上算了,正常的时间也会更长一些。
manatwork 2014年

@Qwertiy,我同意。我希望一些Perl专家可以帮助我解决该问题。
coredump 2014年

@manatwork为什么要计数?
Qwertiy 2014年

@Qwertiy,因为coredump忘记将其从计数中排除。:S可以删除(连同所有这些my关键字)。
manatwork 2014年

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]

取消标注+注释:

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带有自己的time!数据类型。您可以从下面的示例(在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

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)

我不知道如何进一步压缩它。

不打高尔夫球

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)

1

Mathematica 300个字符

这个小练习甚至占用了Mathematica的大量代码。当然,有更有效的方法可以做到这一点。

打高尔夫球

假设输入存储在中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 "}]

工作原理(使用UnGolfed代码):

1-找到时间。

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

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


2分为小时,分钟,秒

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次相加。时间对象是时钟时间。从另一个时间对象减去一个时间对象将返回一个持续时间,在这种情况下为92.0167分钟。 QuantityMagnitude删除度量单位。

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

92.0167


4-将92.0167分钟转换为小时,分钟,秒。

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

1h 32m 1s


1

Perl,146岁

我的条目在输出的末尾加上空格-我希望可以

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"

如果我们假设每行输入只有一次,我们可以砍掉4个字符:

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"

这些工作通过累计经过的总秒数并随后格式化该值来进行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.