我有一个以下形式的三列表数据:
TIME MPID CPID
14:00:04.909 10048 370007
14:00:05.320 10048 370007
14:00:05.462 10048 370008
14:00:05.761 10048 370008
14:00:05.809 10048 370009
14:00:05.833 10048 370009
14:00:11.320 10048 370010
14:00:11.453 10048 370010
14:00:11.693 10048 370011
14:00:13.097 10048 370012
14:00:14.124 10048 370012
这里,TIME 列由 HH:MM:SS.SSS 格式的时间戳组成。MPID 和 CPID 列是标识号;它们的含义对于我的问题并不重要。 MPID 值也不起作用,除了它们存在于数据集中并且需要传播到输出这一事实之外。
我想要的是识别具有匹配 CPID 值的行对并计算它们对应时间之间的差异。例如,上面的示例中有两行(第三行和第四行),CPID 为 77846。对应的时间是 14:00:05.320 和 14:00:05.589,所以我想计算差值:14: 00:04.909 - 14:00:05.320 = 00:00:00.589
我还想以以下格式输出此结果:
MPID 10051 CPID 77846 Total time difference: 589 mili seconds
如果给定的 CPID 在数据集中没有恰好出现两次,那么我想忽略它。
给定示例数据的所需输出应如下所示:
MPID 10051 CPID 77845 Total time difference: 1400 milli seconds
MPID 10051 CPID 77846 Total time difference: 1300 milli seconds
MPID 10051 CPID 77847 Total time difference: 800 milli seconds
MPID 10051 CPID 77848 Total time difference: 1800 milli seconds
MPID 10051 CPID 77849 Total time difference: 1900 milli seconds
目前使用的脚本:
uniq -D -f 2 "${1}" |
while read a b c && read d e f ; do
g=$(( $(date -d $d +%s) - $(date -d $a +%s) ))
printf "MPID %s CPID %s Total time difference: %02i seconds\n" $b $c $g
done
输出给予
MPID 10051 CPID 77845 Total time difference: 00 seconds
MPID 10051 CPID 77846 Total time difference: 03 seconds
MPID 10051 CPID 77847 Total time difference: 12 seconds
MPID 10051 CPID 77848 Total time difference: 15 seconds
MPID 10051 CPID 77849 Total time difference: 19 seconds
答案1
我通过添加三行相同的行来调整您的样本数据CPID
,370013
以表明这些行被拒绝,符合“恰好出现两次”的要求。我还添加了另外两行,CPID
370014
这是我们想要的一对:
TIME MPID CPID
14:00:04.909 10048 370007
14:00:05.320 10048 370007
14:00:05.462 10048 370008
14:00:05.761 10048 370008
14:00:05.809 10048 370009
14:00:05.833 10048 370009
14:00:11.320 10048 370010
14:00:11.453 10048 370010
14:00:11.693 10048 370011
14:00:13.097 10048 370012
14:00:14.124 10048 370012
14:00:14.189 10048 370013
14:00:14.320 10048 370013
14:00:15.020 10048 370013
14:00:16.123 10048 370014
14:00:16.790 10048 370014
跑步:
$ txr data.txr data
MPID 10048 CPID 370007 Total time difference: 411 mili seconds
MPID 10048 CPID 370008 Total time difference: 299 mili seconds
MPID 10048 CPID 370009 Total time difference: 24 mili seconds
MPID 10048 CPID 370010 Total time difference: 133 mili seconds
MPID 10048 CPID 370012 Total time difference: 1027 mili seconds
MPID 10048 CPID 370014 Total time difference: 667 mili seconds
不表示单个370011
条目,也不表示三重条目370013
。
代码:
@(do (defun mk-time-ms (date ms)
(let ((tsec (time-parse-utc "%H:%M:%S" date)))
(+ (* tsec 1000) ms))))
TIME MPID CPID
@(repeat)
@d0.@ms0 @mpid @cpid
@d1.@ms1 @mpid @cpid
@ (collect :gap 0)
@extra @mpid @cpid
@ (end)
@ (do (unless (boundp 'extra)
(let ((t0 (mk-time-ms d0 (toint ms0)))
(t1 (mk-time-ms d1 (toint ms1))))
(put-line `MPID @mpid CPID @cpid Total time difference: @(- t1 t0) mili seconds`))))
@(end)
mk-time-ms
是一个将日期解析为整数(自 Unix 纪元以来的时间)并将其与毫秒值组合的函数。我们将秒时间乘以 1000 再加上毫秒。
我们逐字匹配标题行:
TIME MPID CPID
然后开始@(repeat)
比赛。我们正在寻找以具有相同cpid
( 和mpid
) 的两个连续行开头的行序列。通过附加,@(collect)
我们将附加零个或更多行与相同的mpid
或匹配零个或更多行cpid
。从这些中,我们收集时间列表作为extra
变量。对于每个匹配,如果extra
变量尚未在模式匹配中绑定,则意味着我们恰好匹配了两行,并且没有额外的内容:在这种情况下,我们计算时间差并生成所需的输出。
@(repeat)
跳过任何没有发生比赛的行,这会照顾单打。因为@(collect)
同样,默认情况下,会跳过不匹配的行,所以我们必须严格限制:gap 0
:不允许有任何间隙。否则它将消耗整个数据,而外部@(repeat)
则什么也没有留下。
如果数据中实际上没有任何三重复项,只有成对或单例,则可以是:
@(do (defun mk-time-ms (date ms)
(let ((tsec (time-parse-utc "%H:%M:%S" date)))
(+ (* tsec 1000) ms))))
TIME MPID CPID
@(repeat)
@d0.@ms0 @mpid @cpid
@d1.@ms1 @mpid @cpid
@ (do (let ((t0 (mk-time-ms d0 (toint ms0)))
(t1 (mk-time-ms d1 (toint ms1))))
(put-line `MPID @mpid CPID @cpid Total time difference: @(- t1 t0) mili seconds`)))
@(end)
对于我们的示例数据,现在包括以下输出:
MPID 10048 CPID 370013 Total time difference: 131 mili seconds
前两370013
行被比较并消耗。下一个370013
看起来像单例并且被跳过。如果我们想包含这两个差异,我们可以进行以下修改,包括@(trailer)
在正确的位置添加该行:
@(do (defun mk-time-ms (date ms)
(let ((tsec (time-parse-utc "%H:%M:%S" date)))
(+ (* tsec 1000) ms))))
TIME MPID CPID
@(repeat)
@d0.@ms0 @mpid @cpid
@ (trailer)
@d1.@ms1 @mpid @cpid
@ (do (let ((t0 (mk-time-ms d0 (toint ms0)))
(t1 (mk-time-ms d1 (toint ms1))))
(put-line `MPID @mpid CPID @cpid Total time difference: @(- t1 t0) mili seconds`)))
@(end)
现在这些行出现在输出中:
MPID 10048 CPID 370013 Total time difference: 131 mili seconds
MPID 10048 CPID 370013 Total time difference: 700 mili seconds
第一和第二370013
以及第二和第三之间的区别。
@(trailer)
意味着后面的内容都是尾随上下文:它被匹配,但不被消耗。因此,@(repeat)
尽管匹配了两行,但 now 只消耗一行,导致 的下一次迭代@(repeat)
即使匹配了两行并产生了时间差,也向前移动了一行。