我想说你有一个好的开始,因为你是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”类(或一般意义上的关联数组,如果您尝试从头开始实施),您可以将其用于过滤和计算词频。 –