2014-11-20 64 views
0

我剛剛學習Ruby,並且一直在處理小型代碼項目以加速此過程。Ruby從標準中刪除陣列

我在這裏要做的只是將文本文件中的字母單詞讀入數組,然後刪除數組中長度小於5個字符的單詞。然後,在標準輸出的底部,我打算使用該數組。我的代碼目前工作,但是它非常慢,因爲它必須讀取整個文件,然後單獨檢查每個元素並刪除相應的元素。這似乎是做了太多工作。

goal = File.read('big.txt').split(/\s/).map do |word| 
    word.scan(/[[:alpha:]]+/).uniq 
end 

goal.each { |word| 
    if word.length < 5 
     goal.delete(word) 
    end 
} 

puts goal.sample 

有沒有辦法將標準應用到我的File.read塊,以防止短映射開始?我願意幫助我加快速度。

+0

而不是存儲所有內容,並刪除不應該在那裏,不要將它保存在第一位。這將是一個巨大的改進。 – SlySherZ 2014-11-20 17:43:21

+0

我在下面回答,但我對你的風格有一個評論:你同時使用do..end(對於map)和{..}(對於每個)作爲傳遞塊的方式。一般情況下,除非塊是單行(如{| word | word.upcase!}),否則始終使用do..end – 2014-11-20 18:23:48

+0

將正則表達式更改爲僅匹配大於5個字母的單詞,使代碼在測試用例中運行速度加快了35倍我這樣做......是的:D – SlySherZ 2014-11-20 18:25:11

回答

1

我真的不明白你在第一個循環中所做的很多事情。

您將每個由空格分隔的文本塊都映射到一個數組中的唯一值,該數組通過組合一組字母字符並將其插入數組中。

這對於你想要的東西來說太複雜了。試試這個:

goal = File.readlines('big.txt').select do |word| 
    word =~ /^[a-zA-Z]+$/ && 
    word.length >= 5 
end 

這使得它也很容易添加新的條件。如果單詞不能包含「Q」或「Q」,例如:

goal = File.readlines('big.txt').select do |word| 
    word =~ /^[a-zA-Z]+$/ && 
    word.length >= 5 && 
    ! word.upcase.include? 'Q' 
end 

這是假設在你的字典中的每個字是自己的路線。你可以回到在空白處分割它,但它讓我懷疑你正在閱讀的文件是否是可讀的文本; a.k.a,它具有以句號或逗號結尾的「單詞」,就像這句話一樣。在這種情況下,分割空白將不起作用。

另一個說明 - 地圖是錯誤的數組函數使用。它修改一個數組中的值並從這些值中創建另一個值。你想從數組中選擇某些值,但不能修改它們。 Array#select方法是你想要的。

另外,如果您期待非標準字母字符,隨意修改正則表達式使用:alpha:標記。


編輯:第二個版本

goal = /([a-z][a-z']{4,})/gi.match(File.readlines('big.txt').join(" "))[1..-1] 

說明:加載一個文件,該文件與空間聯合起來的所有線路。捕獲一組字母的所有出現,至少有5個字母,可能包含,但不以'開頭。把所有這些事件放到一個數組中。 [1 ..- 1]丟棄MatchData對象返回的「完全匹配」,這將被附加在一起的所有單詞。

這種運作良好,而且只有一條線路爲您的整個任務,但是,它會匹配

sugar'

I'd like some 'sugar', if you know what I mean

和上面一樣,如果你的字可以」 t包含qQ,您可以將正則表達式更改爲

/[a-pr-z][a-pr-z']{4,})[ .'",]/i

並有一個想法 - 做另一個選擇goal,刪除所有以'結尾的條目。這克服了我的正則表達式的侷限性

+0

這對每行有文字的文件都有效。我使用的文件是福爾摩斯小說的摘錄,這就是爲什麼我使用空白區分這些詞的原因。有沒有辦法來應用這種方法來阻止文本,因爲我同意,通過製作一個數千個小數組我很大可能會使它複雜化? – bubunt205 2014-11-20 21:02:35

+0

當你考慮更強大的單詞情況時,你開始接觸到複雜的正則表達式 - 如果文本中沒有出現'doesn't',是不是'單詞?如果我們的正則表達式很簡單,並且我們捕獲了那個''',那麼我們也可以在引號開始時捕獲''',使得''這個單詞。給我一點點工作。 – 2014-11-21 13:10:28

+0

我編輯了我的答案,添加了一個新的方法。 – 2014-11-21 13:41:57

3

你可能想改變你的正則表達式,而不是隻捕獲的話超過5個字符開始說起:

goal = File.read('C:\Users\bkuhar\Documents\php\big.txt').split(/\s/).flat_map do |word| 
    word.scan(/[[:alpha:]]{6,}/).uniq 
end 

進一步優化可能是維持一個Set而不是Array,以避免重新掃描獨特性:

goal = Set.new 
File.read('C:\Users\bkuhar\Documents\php\big.txt').scan(/\b[[:alpha:]]{6,}\b/).each do |w| 
    goal << w 
end 
+0

您提供的第一個例子效果很好,但不是閱讀超過5個字符的單詞而忽略較短的單詞,而是將較短的單元讀入二維數組目標。 – bubunt205 2014-11-20 20:26:58

+0

我已將'map'更改爲'flat_map'。我已經從你的代碼中取得了「地圖」,這也將產生一個二維數組... – 2014-11-20 20:28:55

+0

@Cary,謝謝你的評論!第一個版本再次是我試圖展示最小改變的解決方案,所以它可能不是我所寫的代碼,但是對於OP來說是最熟悉的。 – 2014-11-21 06:25:53

2

在這種情況下,使用delete_if方法

goal => your array 
goal.delete_if{|w|w.length < 5} 

這將返回一個長度小於5的單詞刪除的新數組。

希望這會有所幫助。

+0

...它不會改善代碼的運行時間......「我的代碼目前正常工作,但由於它必須讀取整個文件,然後單獨檢查每個元素並刪除相應的元素,所以速度非常慢」。 ..我同意使用'delete_if'是以慣用的方式編寫上面的代碼的方式,但它不回答這個問題... – 2014-11-20 18:17:50