我正在处理字符串列表,您可以将它们视为一本书的行。 当一行为空时,必须将其丢弃。当它是标题时,它被“保存”为当前标题。每个“普通”行必须生成一个包含其文本和当前标题的对象。 最后,你有一个行列表,每行都有相应的标题。
例:
- Chapter 1
Lorem ipsum dolor sit amet
consectetur adipisicing elit
- Chapter 2
sed do eiusmod tempor
incididunt u
第一行是标题,必须丢弃第二行,然后将两行保存为段落,每行以“第1章”作为标题。等等。最终得到类似于:
的集合{"Lorem ipsum...", "Chapter 1"},
{"consectetur...", "Chapter 1"},
{"sed do...", "Chapter 2"},
{"incididunt ...", "Chater 2"}
我知道标题/段落模型没有100%的意义,但我简化了模型以说明问题。
这是我的迭代解决方案:
let parseText allLines =
let mutable currentTitle = String.Empty
seq {
for line in allLines do
match parseLine line with
| Empty -> 0 |> ignore
| Title caption ->
currentTitle <- caption
| Body text ->
yield new Paragraph(currentTitle, text)
}
第一个问题是我必须丢弃空行,我用0 |> ignore
来做,但对我来说这看起来很糟糕。有什么做到这一点(没有预先过滤列表)?
此函数的尾递归版本很简单:
let rec parseText allLines currentTitle paragraphs =
match allLines with
| [] -> paragraphs
| head :: tail ->
match head with
| Empty -> parseText tail currentTitle paragraphs
| Title caption -> parseText tail caption paragraphs
| Body text -> parseText tail currentTitle (new Paragraph(currentTitle, text) :: tail)
问题:
答案 0 :(得分:2)
您可以将0 |> ignore
替换为()
(单位),这是一个无操作。两个实现之间的最大区别是第一个是懒惰的,这可能对大输入有用。
以下内容对您也有用(这是我能想到的最简单的解决方案):
let parseText (lines:seq<string>) =
lines
|> Seq.filter (fun line -> line.Trim().Length > 0)
|> Seq.pairwise (fun (title, body) -> Paragraph(title, body))
如果没有,也许这会奏效:
let parseText (lines:seq<string>) =
lines
|> Seq.choose (fun line ->
match line.Trim() with
| "" | null -> None
| Title title -> Some title
| Body text -> Some text)
|> Seq.pairwise (fun (title, body) -> Paragraph(title, body))
答案 1 :(得分:2)
虽然不是一个List.Map,但这是我提出的解决方案:
let parseText allLines =
allLines
|> Seq.fold (fun (currentTitle,paragraphs) line ->
match parseLine line with
| Empty -> currentTitle,paragraphs
| Title caption -> caption,paragraphs
| Body text -> String.Empty,Paragraph(currentTitle, text)::paragraphs
) (String.Empty,[])
|> snd
我正在使用(currentTitle,paragraphs)
作为状态的折叠。 snd
用于提取结果(它是状态元组的 s eco nd 部分)。
当您在F#中进行大部分处理时,使用列表非常诱人,但其他数据结构,甚至普通序列都有其用途。
顺便说一下,您的序列码是否编译?我必须将mutable currentTitle = String.Empty
替换为currentTitle = ref String.Empty
。
答案 2 :(得分:1)
下面是一个这样的实现(虽然没有经过测试,但我希望它能给你这个想法)
let isNotEmpty l = match l with
| Empty -> false
| _ -> true
let parseText allLines =
allLines |> Seq.map parseLine |> Seq.filter isNotEmpty
|> Seq.scan (fun (c,t,b) i -> match i with
| Title tl -> (0,tl,"")
| Body bb -> (1,t,bb)
| _ -> (0,t,b)) (0,"","")
|> Seq.filter (fun (c,_,_) -> c > 0)
|> Seq.map (fun (_,t,b) -> Paragraph(t,b) )