F#:将旧的 IEnumerable.GetEnumerator() 样式迭代器转换为 seq

mt9*_*t99 5 f#

IEnumerable.GetEnumerator().NET 标准库中仍然有一些东西只向外界公开旧式迭代器,这对 F# seq 处理风格不太友好。我正在快速谷歌搜索如何将 a 的结果组Regex.Match(...)放入我可以处理的列表中,但没有找到任何内容。

我有这个:

open System.Text.RegularExpressions
let input = "args=(hello, world, foo, bar)"
let mtc = Regex.Match( input, "args=\(([\w\s,]+)\)" )
Run Code Online (Sandbox Code Playgroud)

我想要的是mtc.Groups作为 seq 或作为列表进行访问,但它不允许这样做,因为它是 ye olde ICollection,它只公开一个GetEnumerator()方法。所以虽然你可以做

mtc.Groups.[1].Value
Run Code Online (Sandbox Code Playgroud)

你不能做

mtc.Groups |> Seq.skip 1 // <=== THIS QUESTION IS ABOUT HOW TO ACHIEVE THIS
Run Code Online (Sandbox Code Playgroud)

因为这导致

error FS0001: The type 'Text.RegularExpressions.GroupCollection' is not compatible with the type 'seq<'a>
Run Code Online (Sandbox Code Playgroud)

(为了清楚起见,GroupCollection实现了ICollection,它是 的子接口IEnumerable。)

所以问题是:如何巧妙地将 a 转换GetEnumerator()为 seq?

mt9*_*t99 5

答案其实并不复杂,只是为下一个在谷歌上搜索快速答案的人提供的。这个想法是将可怕的命令性包装在seq {...}表达式中,然后将结果转换seq<obj>为您碰巧知道的结果。

seq { let i = mtc.Groups.GetEnumerator() in while i.MoveNext() do yield i.Current } 
|> Seq.cast<Text.RegularExpressions.Group> 
|> Seq.map (fun m -> m.Value)
|> List.ofSeq
Run Code Online (Sandbox Code Playgroud)

当对上述输入运行时,会产生所需的输出:

val input : string = "args=(hello, world, foo, bar)"
val mtc : Match = args=(hello, world, foo, bar)
val it : string list = ["args=(hello, world, foo, bar)"; "hello, world, foo, bar"]
Run Code Online (Sandbox Code Playgroud)

正如我所说,我将其放在这里供下一个谷歌搜索答案,因此欢迎改进、建议、反对票、欺骗标志。

编辑:根据第一条评论中的建议,Seq.cast足够聪明,可以IEnumerable直接吃 s 。所以 seq 表达式根本没有必要,答案就是Seq.cast<Text.RegularExpressions.Group>!让我知道我是否应该删除这个问题。

  • 您不应该需要 `seq` 表达式 - `mtc.Groups |&gt; Seq.cast&lt;Group&gt;` 也应该可以工作。 (6认同)