2013-10-28 114 views
1

什麼是最好的方式來同時迭代兩個文件,所以如果file_1 =='x'中的第57行然後用這種方式處理file_2中的第57行?循環遍歷兩個文件Ruby

下面我的代碼無法正常工作,但我知道有一個簡單的解決方案有...

@blue = [] 
@red = [] 

file_1 = File.open('index.txt', 'r') 
file_2 = File.open('index2.txt', 'r') 

for item, line in file_1, file_2 
    @blue << line if item == "blue" 
    @red << line if item == "red" 
end 

file_1.close 
file_2.close 
+0

如果文件長度不同(=行數)會發生什麼? –

+0

我不能完全按照你的循環,可能是我對Ruby的無知,但你在那裏; 'item'是'file_1'的行,'line_2'是'file_2'的行嗎? – glenatron

+0

@glenatron是的,這是我的基本前提 –

回答

2

這是從未一個很好的做法,讀一展身手整個文件,並放置在一個變量。

對於你的問題,這需要兩個文件的併發讀取,我會建議這個(它不需要任何形式的空間開銷):

@blue = [] 
@red = [] 
#make the files enumerable. 
file_1 = File.open('index.txt', 'r').to_enum 
file_2 = File.open('index2.txt', 'r').to_enum 

loop do 
    #access next line in each file with .next 
    item = file_1.next 
    line = file_2.next 
    @blue << line if item.eql?('blue') 
    @red << line if item.eql?('red') 
end 

file_1.close 
file_2.close 

to_enum呼籲對象時,使得它和枚舉裝備了幾個枚舉器功能。 #next是其中一種內置方法。

上面的代碼從每個文件中逐一讀取一行;循環將立即終止,只要有任何文件輸出下一個輸入。

+0

爲什麼它永遠不是好的做法? – iamnotmaynard

+0

你的意思是,閱讀兩個文件(比如說每個2GB)並將其存儲在某個變量中是值得推薦的?即使文件不是那麼大,如果它提供了一個這樣的東西呢? – kiddorails

+0

不,閱讀兩個2 gig的文件通常不值得推薦(雖然它可能仍然沒有問題)。大約10億個文件讀數也不是。在這種情況下,程序可能應該使用sql或其他數據庫解決方案。這並不回答爲什麼它從來沒有**良好的做法;如果這些文件不是不切實際的大,那很好。 – iamnotmaynard

2

我敢肯定有一個更好的辦法,但它的作品調用的文件IO#readlineszip他們像這樣:

for item, line in file_1.readlines.zip(file_2.readlines) 

只要文件不是太大(也就是非常大),應該沒有問題的全部閱讀。您可能需要事先檢查文件是否具有相同的行數,以避免意外的行爲。

+0

定義'非常大'。如果我的系統具有640k的內存,那麼非常大的內存就不是很大,不到一兆。如果它有32場演唱會,那麼非常大的是另一回事。 「非常大」不可能非常有幫助。 – vgoff

+0

如果有人正在處理一些可以被普通用戶使用的東西,那麼他應該考慮到在該系統中讀取的文件不是「非常大的」。這是假設的;但是,這又是相對於定義而言的。 – kiddorails

+0

@vgoff「非常大」與其運行的系統相比意味着非常大。這是主觀的,但我想你會在看到它時知道它。我懷疑OP是否打算將它用於具有一百萬行的文件,儘管如此,任何現代系統都可以很好地處理它。另外,如果你的系統有640k我懷疑它可以運行Ruby。 – iamnotmaynard

1

您可能會發現使用File.readlines()從每個文件創建一個數組更容易,然後對這些數組進行操作,而不是直接處理文件數據。事情是這樣的,也許:

@blue = [] 
@red = [] 

file_1 = File.open('index.txt', 'r') 
file_2 = File.open('index2.txt', 'r') 

red_vs_blue = file_1.readlines() 
lines = file_2.readlines() 

red_vs_blue.zip(lines) 

red_vs_blue.each do | item, line | 
    @blue << line if item == "blue" 
    @red << line if item == "red" 
end