[英]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 解析器之外,沒有辦法做你想做的事。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.