2013-06-30 29 views
10

我剛開始使用F#並試圖理解典型的idoms和有效的思維和工作方式。F#中的文件轉換#

手頭的任務是將製表符分隔的文件簡單轉換爲逗號分隔的文件。一個典型的輸入線將看起來像:

let line = "@ES# 01/31/2006 13:31:00 1303.00 1303.00 1302.00 1302.00 2514 0" 

我開始了循環這樣的代碼:

// inFile and outFile defined in preceding code not shown here 

for line in File.ReadLines(inFile) do 
    let typicalArray = line.Split '\t' 
    let transformedLine = typicalArray |> String.concat "," 
    outFile.WriteLine(transformedLine) 

我再換成分流/的concat操作對與單個Regex.Replace():

for line in File.ReadLines(inFile) do 
    let transformedLine = Regex.Replace(line, "\t",",") 
    outFile.WriteLine(transformedLine) 

而現在,終於,更換了管道的循環:

File.ReadLines(inFile) 
    |> Seq.map (fun x -> Regex.Replace(x, "\t", ",")) 
    |> Seq.iter (fun y -> outFile.WriteLine(y)) 

    // other housekeeping code below here not shown 

儘管所有版本都有效,但最終版本在我看來最直觀。這是一個更有經驗的F#程序員如何完成這項任務嗎?

+0

我會以同樣的方式做到這一點 –

+1

我會在第三個版本的最後一行忽略匿名函數,只是這樣做:'|> Seq.iter outFile.WriteLine' –

+1

這是一個非常好的[和, **回顧**,明顯的]簡化。謝謝! – akucheck

回答

11

我認爲所有三個版本都是F#專家會寫的非常好的慣用代碼。

我通常更喜歡使用內置語言功能(如for環和if條件)編寫代碼,如果他們讓我解決我的問題。這些都是必要的,但我認爲使用它們是一個好主意,當API需要命令代碼時(如outFile.WriteLine)。正如你所提到的 - 你從這個版本開始(我會做同樣的)。

使用高階函數也不錯 - 雖然我可能會做,只有當我想寫數據轉型,並得到一個新的序列或行列表 - 這將是方便的,如果你使用File.WriteAllLines代替寫一行一行。雖然,這可以通過簡單地與序列式包裝你的第二個版本也做:

let transformed = 
    seq { for line in File.ReadLines(inFile) -> Regex.Replace(line, "\t",",") } 
File.WriteAllLines(outFilePath, transformed) 

我不認爲有任何客觀原因更喜歡的版本之一。我個人的風格偏好是使用for並重構序列表達式(如果需要),但其他人可能會不同意。

+0

謝謝,托馬斯 - 非常感謝。 – akucheck