为什么我不能用`count`对字符串数组进行排序?

时间:2015-09-10 22:40:48

标签: ruby string sorting

使用此代码:

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"]

在这种情况下,按计数排序不起作用吗?为什么?有没有更好的方法来按频率隔离单词?

2 个答案:

答案 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]