2011-10-02 62 views
1

讓我們這樣的代碼:是否有一種更通用的方式來迭代,過濾,對F#中的集合應用操作?

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

爲了效率。 – BLUEPIXY

回答

5

您可能會或可能不會需要跟蹤的你處理什麼類型的集合,根據您的情況。

簡單迭代的情況下,在項目沒有什麼可以阻止您使用在F#列表或數組Seq.iter:它將工作在數組以及超過列爲二者也序列或.NET的角度來看IEnumerable秒。在列表上使用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 
2

列表和數組被視爲Seq。

let printAll seqData = 
    seqData |> Seq.iter (printfn "%A") 
    Console.ReadLine() |> ignore 

printAll lines 
printAll [1..10] 
printAll [|1..10|] 
4

Seq.iter也適用於列表和數組。

類型seq實際上是接口IEnumerable<'T>的別名,其中listarray都執行。因此,正如BLUEPIXY指出的那樣,您可以在陣列或列表上使用Seq.*函數。

一個不太實用的前瞻性的方法是如下:

for x in [1..10] do 
    printfn "%A" x 
相關問題