我们来看看这段代码:
open System
open System.IO
let lines = seq {
use sr = new StreamReader(@"d:\a.h")
while not sr.EndOfStream do yield sr.ReadLine()
}
lines |> Seq.iter Console.WriteLine
Console.ReadLine()
在这里,我正在阅读seq
中的所有行,并且要查看它,我正在使用Seq.iter
。如果我有一个列表,我将使用List.iter
,如果我有一个数组,我将使用Array.iter
。是不是我可以使用更通用的遍历功能,而不是必须跟踪我有什么样的集合?例如,在Scala中,我只会调用foreach
,无论我使用的是List,Array还是Seq,它都能正常工作。
我做错了吗?
答案 0 :(得分:5)
根据您的具体情况,您可能需要或不需要跟踪您处理的收藏类型。
如果对项目进行简单的迭代,没有什么可能阻止您在F#中的列表或数组上使用Seq.iter
:它将在数组和列表上工作,因为它们也是序列,或IEnumerable
从.NET的角度来看。在数组上使用Array.iter
或在列表上使用List.iter
只会根据每种类型的集合的特定属性提供更有效的遍历实现。由于Seq.iter Seq.iter : ('T -> unit) -> seq<'T> -> unit
的签名显示您在遍历后不关心您的类型'T
。
在其他情况下,如果您关心进一步的构图,您可能需要考虑输入和输出参数的类型并使用专门的函数。例如,如果您需要过滤列表并继续使用结果,那么
List.filter : ('T -> bool) -> 'T list -> 'T list
会保留底层集合的完整类型,但是Seq.filter : ('T -> bool) -> seq<'T> -> seq<'T>
应用于列表会返回一个序列,而不再是列表:
let alist = [1;2;3;4] |> List.filter (fun x -> x%2 = 0) // alist is still a list
let aseq = [1;2;3;4] |> Seq.filter (fun x -> x%2 = 0) // aseq is not a list anymore
答案 1 :(得分:4)
Seq.iter
也适用于列表和数组。
类型seq
实际上是接口IEnumerable<'T>
的别名,list
和array
都是实现的。因此,正如BLUEPIXY指出的那样,您可以在数组或列表上使用Seq.*
函数。
功能较少的方式如下:
for x in [1..10] do
printfn "%A" x
答案 2 :(得分:2)
列表和数组被视为Seq。
let printAll seqData =
seqData |> Seq.iter (printfn "%A")
Console.ReadLine() |> ignore
printAll lines
printAll [1..10]
printAll [|1..10|]