使用此代码:
line = ("Ignore punctuation, please :)")
string = line.strip.downcase.split(//)
string.select! {|x| /[a-z]/.match(x) }
string.sort_by!{ |x| string.count(x)}
结果是:
["r", "g", "s", "l", "c", "o", "o", "p", "u", "i", "t", "u", "a", "t", "i", "a", "p", "n", "e", "e", "n", "n", "e"]
在这种情况下,按计数排序不起作用吗?为什么?有没有更好的方法来按频率隔离单词?
答案 0 :(得分:2)
根据您的评论,我认为您希望按频率和字母顺序对字符进行排序。当唯一的sort_by!
条件为string.count(x)
时,具有相同字符数的频率组可能会相互混淆。要按字母顺序对每个组进行排序,您必须在sort_by!
方法中添加第二个条件:
line = ("Ignore punctuation, please :)")
string = line.strip.downcase.split(//)
string.select! {|x| /[a-z]/.match(x) }
string.sort_by!{ |x| [string.count(x), x]}
然后输出
["c", "g", "l", "r", "s", "a", "a", "i", "i", "o", "o", "p", "p", "t", "t", "u", "u", "e", "e", "e", "n", "n", "n"]
答案 1 :(得分:1)
让我们逐行查看您的代码。
line = ("Ignore punctuation, please :)")
s = line.strip.downcase
#=> "ignore punctuation, please :)"
strip
这里没有特别的理由,因为无论如何你将删除空格和标点符号。
string = s.split(//)
#=> ["i", "g", "n", "o", "r", "e", " ", "p", "u", "n", "c", "t",
# "u", "a", "t", "i", "o", "n", ",", " ", "p", "l", "e", "a",
# "s", "e", " ", ":", ")"]
你选择将句子分成字符,这很好,但正如我最后提到的,你可以使用String
方法。无论如何,
string = s.chars
做同样的事情,可以说更清楚。你现在拥有一个名为string
的数组。这有点令人困惑吗?我们改为称之为arr
:
arr = s.chars
(对于数组的名称s
和{{1}对于哈希的名称,等等。)
str
现在你已经删除了所有小写字母。你也可以这样写:
a
或
arr
您现在可以进行排序了。
h
这没关系,但是将数组排序到位并同时计算其元素的频率并不是一个好习惯。更好的是:
hash
给出相同的顺序。生成的排序数组是否正确?让我们计算每个字母出现在字符串中的次数。
我将创建一个哈希,其键是arr.select! {|x| /[a-z]/.match(x) }
#=> ["i", "g", "n", "o", "r", "e", "p", "u", "n", "c", "t", "u",
# "a", "t", "i", "o", "n", "p", "l", "e", "a", "s", "e"]
的唯一元素,其值是相关键在arr.select! {|x| s =~ /[a-z]/ }
中出现的次数。有几种方法可以做到这一点。一种简单但不是非常有效的方法如下:
arr.select! {|x| s[/[a-z]/] }
这通常会写成:
arr.sort_by!{ |x| arr.count(x) }
#=> ["l", "g", "s", "c", "r", "i", "p", "u", "a", "o", "t", "p",
# "a", "t", "i", "o", "u", "n", "n", "e", "e", "n", "e"]
arr1 = arr.sort_by{ |x| arr.count(x) }
的元素按价值递增,但这只是巧合。为了确保它们按顺序排列(以便更容易查看顺序),我们需要构造一个数组,对其进行排序,然后将其转换为哈希:
arr
人们通常会看到这样写:
arr
或者,在Ruby v2.0 +中:
h = {}
a = arr.uniq
#=> ["l", "g", "s", "c", "r", "i", "p", "u", "a", "o", "t", "n", "e"]
a.each { |c| h[c] = arr.count(c) }
h #=> {"l"=>1, "g"=>1, "s"=>1, "c"=>1, "r"=>1, "i"=>2, "p"=>2,
# "u"=>2, "a"=>2, "o"=>2, "t"=>2, "n"=>3, "e"=>3}
请注意,在Ruby 1.9之前,没有哈希中键排序的概念。
h = arr.uniq.each_with_object({}) { |c,h| h[c] = arr.count(c) }
键值对的值表明您的排序是正确的。然而,它不是非常有效。那是因为在:
h
你反复遍历a = arr.uniq.map { |c| [c, arr.count(c)] }
#=> [["l", 1], ["g", 1], ["s", 1], ["c", 1], ["r", 1], ["a", 2], ["p", 2],
# ["u", 2], ["i", 2], ["o", 2], ["t", 2], ["n", 3], ["e", 3]]
a = a.sort_by { |_,count| count }
#=> [["l", 1], ["g", 1], ["s", 1], ["c", 1], ["r", 1], ["a", 2], ["t", 2],
# ["u", 2], ["i", 2], ["o", 2], ["p", 2], ["n", 3], ["e", 3]]
h = Hash[a]
#=> {"l"=>1, "g"=>1, "s"=>1, "c"=>1, "r"=>1, "i"=>2, "t"=>2,
# "u"=>2, "a"=>2, "o"=>2, "p"=>2, "n"=>3, "e"=>3}
,计算元素的频率。最好构造上面的哈希:
h = Hash[arr.uniq.map { |c| [c, arr.count(c)] }.sort_by(&:last)]
在执行排序之前,然后:
h = arr.uniq.map { |c| [c, arr.count(c)] }.sort_by(&:last).to_h
顺便说一下,让我提一个更有效的方法来构建哈希h
,只需要一次通过arr.sort_by { |x| arr.count(x) }
:
arr
或者,更简洁:
h = arr.uniq.each_with_object({}) { |c,h| h[c] = arr.count(c) }
此处arr.sort_by { |x| h[x] }
称为计算哈希:
h
创建一个空哈希,其默认值为零。这意味着,如果arr
没有密钥h = Hash.new(0)
arr.each { |x| h[x] += 1 }
h #=> {"l"=>1, "g"=>1, "s"=>1, "c"=>1, "r"=>1, "a"=>2, "p"=>2,
# "u"=>2, "i"=>2, "o"=>2, "t"=>2, "n"=>3, "e"=>3}
,则h = arr.each_with_object(Hash.new(0)) { |x,h| h[x] += 1 }
将返回零。 abbreviated assignment h
扩展为:
h = Hash.new(0)
如果h
没有密钥k
,则默认值会分配给右侧的h[k]
:
h[c] += 1
但是下次遇到h[c] = h[c] + 1
时:
h
最后,让我们重新开始,尽可能使用c
方法:
h[c]