簡體   English   中英

在 go 中從文本文件中讀取隨機行

[英]Read random lines off a text file in go

我正在使用encoding/csv來讀取和解析一個非常大的 .csv 文件。
我需要隨機選擇行並通過一些測試。
我目前的解決方案是讀取整個文件,如

reader := csv.NewReader(file)
lines, err := reader.ReadAll()

然后從lines隨機選擇lines
明顯的問題是閱讀整個內容需要很長時間,而且我需要大量內存。

題:
我的問題是, encoding/csv給了我一個io/reader有沒有辦法用它來讀取隨機行而不是一次加載整個東西?
這更像是一種對io/reader的好奇心,而不是一個實際問題,因為很可能最終讀取一次並在內存中訪問它更有效,而不是繼續尋找隨機行盤。

Apokalyptik 的答案最接近你想要的。 讀者是流媒體,所以你不能只是跳到一個隨機的地方(本身)。

天真地選擇在讀入時保留任何給定行的概率可能會導致問題:您可能在沒有保留足夠多的輸入行的情況下到達文件的末尾,或者您可能太快地保留行而沒有得到很好的樣本。 兩者都比正確猜測更有可能,因為您事先不知道文件中有多少行(除非您先迭代一次以計算它們)。

您真正需要的是水庫取樣

基本上,逐行讀取文件。 每一行,您都可以選擇是否持有它:您閱讀的第一行,您有1/1機會持有它。 閱讀第二行后,您有1/2機會用這一行替換您所持有的內容。 在第三行之后,您有1/2 * 2/3 = 1/3機會抓住那一行。 因此,您有1/N機會保持在任何給定的行上,其中N是您讀入的行數。這是對算法更詳細的了解(不要試圖僅根據我的方法來實現它僅在本段中告訴您)。

最簡單的解決方案是在閱讀每一行時做出決定,是測試它還是丟棄它......讓你的決定隨機化,這樣你就不需要將整個東西保存在 RAM 中......然后通過運行測試后通過文件...您也可以使用非隨機分布測試(例如在 X 字節或 X 行等之后)執行相同的樣式

我的建議是提前隨機化輸入文件,例如使用 shuf

http://en.wikipedia.org/wiki/Shuf

然后您可以根據需要簡單地閱讀前 n 行。

這無助於您更多地了解 io/readers,但可能會解決您的問題。

我有類似的需求:從大量文本文件中隨機讀取(特定)行。 我寫了一個我稱之為ramcsv的包來做到這一點。

它首先讀取整個文件一次並標記每一行的字節偏移量(它將此信息存儲在內存中,但不存儲整行)。

當您請求一個行號時,它會透明地尋找正確的偏移量並為您提供 csv 解析的行。

(請注意,作為第二個參數傳遞給 ramcsv.New 的 csv.Reader 參數僅用於將設置復制到新的讀取器中。)這無疑可以提高效率,但它足以滿足我的需要並且省去了我將一個 ~20GB 的文本文件讀入內存。

encoding/csv不會給你一個io.Reader它給你一個csv.Reader (注意csv.NewReader [1] 的定義缺少包限定,表明它返回的Reader屬於同一個包。

一個csv.Reader只實現你在那里看到的方法,所以看起來除了編寫自己的 CSV 解析器之外,沒有辦法做你想做的事。

[1] http://golang.org/pkg/encoding/csv/#NewReader

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM