我想說你有一個好的開始,因爲你是Ruby的新手。你問是否應該使用冒泡排序。我想你正在考慮將一個單詞的多次出現分組,然後通過數組來計算它們。這會起作用,但還有其他一些方法更容易,更像「類Ruby」。 (我的意思是說,他們利用語言的強大功能,同時更自然。)
讓我們專注於統計單行中的唯一字。一旦你可以做到這一點,你應該能夠輕鬆地將其推廣到多行。
第一種方法:使用哈希
第一種方法是使用哈希值。 h = {}
創建一個新的空的。散列的鍵將是單詞,其值將是每個單詞出現在該行中的次數。例如,如果單詞「貓」出現9次,我們將有h["cat"] = 9
,正是你需要的。爲了構造這個散列,我們看到該行中的每個單詞w
是否已經在散列中。這是哈希如果
h[w] != nil
如果是,我們增加字數:
h[w] = h[w] + 1
或只是
h[w] += 1
如果它不是在哈希,我們加字到這樣的散列:
h[w] = 1
那m是指合同,我們可以這樣做:
if h[w]
h[w] += 1
else
h[w] = 1
end
注意,這裏if h[w]
相同if h[w] != nil
。
其實,我們可以用一個技巧來使這更簡單。如果我們創建這樣的哈希:
h = Hash.new(0)
然後,我們添加的任何沒有值的鍵將被分配默認值爲零。這樣我們就不必檢查這個單詞是否已經在散列中;我們簡單地寫
h[w] += 1
如果w
不在哈希,h[w]
將增加,並把它初始化爲0
,然後+= 1
將它遞增到1
。很酷,呃?
讓我們把所有這些放在一起。假設
line = "the quick brown fox jumped over the lazy brown fox"
我們這個字符串轉換成數組與String#split
方法:
arr = line.split # => ["the", "quick", "brown", "fox", "jumped", \
"over", "the", "lazy", "brown", "fox"]
然後
h = Hash.new(0)
arr.each {|w| h[w] += 1}
h # => {"the"=>2, "quick"=>1, "brown"=>2, "fox"=>2, "jumped"=>1, "over"=>1, "lazy"=>1}
我們就大功告成了!
第二種方法:每當你想一個數組,散列或其它集合族元素使用Enumerable#group_by
方法
,該group_by
方法應該浮現在腦海中。
要將group_by
應用於快速棕色狐狸陣列,我們提供了一個包含分組標準的塊,在這種情況下,該分組標準本身就是單詞。這將產生一個散列:
g = arr.group_by {|e| e}
# => {"the"=>["the", "the"], "quick"=>["quick"], "brown"=>["brown", "brown"], \
# "fox"=>["fox", "fox"], "jumped"=>["jumped"], "over"=>["over"], "lazy"=>["lazy"]}
接下來要做的是轉換散列值到字(例如,轉換到["the", "the"]
2
)的出現的次數。要做到這一點,我們可以創建一個新的空哈希h
,並添加哈希對吧:
h = {}
g.each {|k,v| h[k] = v.size}
h # => {"the"=>2, "quick"=>1, "brown"=>2, "fox"=>2, "jumped"=>1, "over"=>1, "lazy"=>1
一件事
你有這樣的代碼片段:
if(p[i] != "the" and p[i] != "to" and p[i] != "union" and p[i] != "political")
print p[i] + " "
end
這裏有幾種方法可以使這一點更清潔,都使用上面的散列h
。
第一種方式
skip_words = %w[the to union political] # => ["the", "to", "union", "political"]
h.each {|k,v| (print v + ' ') unless skip_words.include?(k)}
第二種方式
h.each |k,v|
case k
when "the", "to", "union", "political"
next
else
puts "The word '#{k}' appears #{v} times."
end
end
編輯解決您的評論。試試這個:
p = "The quick brown fox jumped over the quick grey fox".split
freqs = Hash.new(0)
p.each {|w| freqs[w] += 1}
sorted_freqs = freqs.sort_by {|k,v| -v}
sorted_freqs.each {|word, freq| puts word+' '+freq.to_s}
=>
quick 2
fox 2
jumped 1
The 1
brown 1
over 1
the 1
grey 1
通常情況下,ypu不會排序散列;而你會先將其轉換爲一個數組:
sorted_freqs = freqs.to_a.sort_by {|x,y| v}.reverse
或
sorted_freqs = freqs.to_a.sort_by {|x,y| -v}
現在sorted_freqs
是一個數組,而不是一個哈希值。最後一行保持不變。一般來說,最好不要依賴哈希的順序。事實上,在Ruby 1.9.2之前,哈希並沒有被排序。如果順序很重要,請使用數組或將哈希轉換爲數組。儘管如此,您可以對散列值進行從最小到最大的排序,或者(如我所做的那樣)對散列值的負值進行從最大到最小的排序。請注意,沒有Enumerable#reverse
或Hash#reverse
。或者(有很多方法對皮膚使用Ruby貓),你可以排序v
然後用Enumerable#reverse_each
:
sorted_freqs.reverse_each {|word, freq| puts word+' '+freq.to_s}
最後,您可以消除臨時變量sorted_freqs
(必要的,因爲沒有Enumerable#sort_by!
方法),通過鏈接最後兩條語句:
freqs.sort_by {|k,v| -v}.each {|word, freq| puts word+' '+freq.to_s}
您需要的算法 - 唯一性,排序,過濾 - 已經在Ruby的Array類中實現。如果這是你課程的目的,那麼也可以直接重新實施它們 - 你最好的選擇就是谷歌算法的名稱。大多數Ruby編程人員只會使用內置函數 - 請參閱http://ruby-doc.org/core-2.0.0/Array.html並查看方法列表 –
您還應該瞭解「Hash」類(或一般意義上的關聯數組,如果您嘗試從頭開始實施),您可以將其用於過濾和計算詞頻。 –