gpt4 book ai didi

F# 将一个 seq 映射到另一个长度较短的 seq

转载 作者:行者123 更新时间:2023-12-02 09:32:37 28 4
gpt4 key购买 nike

我有一个像这样的字符串序列(文件中的行)

[20150101] error a
details 1
details 2
[20150101] error b
details
[20150101] error c

我试图将其映射到这样的字符串序列(日志条目)

[20150101] error a details 1 details 2
[20150101] error b details
[20150101] error c

我可以用命令式的方式做到这一点(通过翻译我用 C# 编写的代码)——这可以工作,但它读起来像伪代码,因为我省略了引用的函数:

let getLogEntries logFilePath =  
seq {
let logEntryLines = new ResizeArray<string>()

for lineOfText in getLinesOfText logFilePath do
if isStartOfNewLogEntry lineOfText && logEntryLines.Any() then
yield joinLines logEntryLines
logEntryLines.Clear()
logEntryLines.Add(lineOfText)

if logEntryLines.Any() then
yield joinLines logEntryLines
}

是否有更实用的方法来做到这一点?

我无法使用Seq.map因为它不是一对一的映射,并且 Seq.fold似乎不对,因为我怀疑它会在返回结果之前处理整个输入序列(如果我有非常大的日志文件,那就不太好)。我认为上面的代码不是在 F# 中执行此操作的理想方法,因为它使用 ResizeArray<string> .

最佳答案

一般来说,当没有可以使用的内置函数时,解决问题的函数式方法是使用递归。在这里,您可以递归地遍历输入,记住最后一个 block 的项目(从最后一个 [xyz] Info 行开始),并在到达新的起始 block 时生成新结果。在 F# 中,您可以使用序列表达式很好地编写此代码:

let rec joinDetails (lines:string list) lastChunk = seq {
match lines with
| [] ->
// We are at the end - if there are any records left, produce a new item!
if lastChunk <> [] then yield String.concat " " (List.rev lastChunk)
| line::lines when line.StartsWith("[") ->
// New block starting. Produce a new item and then start a new chunk
if lastChunk <> [] then yield String.concat " " (List.rev lastChunk)
yield! joinDetails lines [line]
| line::lines ->
// Ordinary line - just add it to the last chunk that we're collection
yield! joinDetails lines (line::lastChunk) }

以下示例显示了正在运行的代码:

let lines = 
[ "[20150101] error a"
"details 1"
"details 2"
"[20150101] error b"
"details"
"[20150101] error c" ]

joinDetails lines []

关于F# 将一个 seq 映射到另一个长度较短的 seq,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31245762/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com