我有一个日志文件,其行开头像这样......
2016-01-06 16:06:52,778 [1]DEBUG ...blah blah blah
我想解析这个文件,并将从前一个日志行开始的经过时间添加到下一个日志的开头.例如,如果我有这样的行......
2016-01-06 16:06:52,000 [1]DEBUG ... 2016-01-06 16:06:52,100 [1]DEBUG ... 2016-01-06 16:06:52,030 [1]DEBUG ...
...然后我想生产以下......
0 2016-01-06 16:06:52,000 [1]DEBUG ... 100 2016-01-06 16:06:52,100 [1]DEBUG ... 30 2016-01-06 16:06:52,130 [1]DEBUG ...
...其中每行的第一个数字是自上一行以来的毫秒数.
现在在C#中,我会使用一个(可变的)变量来保持前一次,然后从中减去新的时间,给我一个失效.但是,我认为变量是你应该在F#中避免的东西,所以想知道它应该如何完成.
到目前为止,我有一个函数将文件读入一个序列,以及以下函数从一行中提取时间(我不担心这种情况下的日期,因为所有时间都在同一天) ...
let parseDate (s:string) = let time = ((s.Split [|' '|]) |> Seq.nth 1).Replace(",", ".") DateTime.Parse(time)
我可以执行以下操作,这会添加自第一次输入以来的总毫秒数...
let start = logLines |> Seq.head |> parseDate let linesWithTimes = logLines |> Seq.map (fun l -> (((parseDate l) - start).TotalMilliseconds).ToString() + " "+ l )
如何添加自上次日志条目以来经过的时间?
希望很清楚.我是F#的新手,所以如果有更好的方法,请告诉我.
有很多方法,这里有一个解决方案Seq.pairwise
:
let linesWithTimes = logLines |> Seq.map (fun x -> parseDate x, x) |> Seq.pairwise |> Seq.map (fun ((dt1, x1), (dt2, x2)) -> string (dt2 - dt1).TotalMilliseconds + " " + x2) |> Seq.append (seq ["0 " + Seq.head logLines])
另一种进行映射但在元素之间组合值的方法是使用折叠:
let linesWithTimes = logLines |> Seq.fold (fun s t -> let dt = parseDate t match s with | None , _ -> Some dt, ["0 " + t] | Some d, lst -> Some dt, lst @ [string (dt - d).TotalMilliseconds + " " + t] ) (None , []) |> snd |> List.toSeq
这是一个使用序列表达式的解决方案,它更长并且它使用了一个可变的但是在可枚举非常长且遍历慢的情况下它可能更合适:
let linesWithTimes = let mutable prev = None : DateTime option seq { for e in logLines do let dt = parseDate e let diff = match prev with | None -> 0. | Some t -> (dt - t).TotalMilliseconds yield string diff + " " + e prev <- Some dt }