如何计算Ruby字符串中唯一的多个单词?

时间:2018-12-21 06:05:11

标签: ruby string block

尝试编写一个Ruby代码,该代码将计算唯一单词并返回其总出现次数。

因此,假设我想在下面的句子中找到Sally,Marina和Tina的出现次数:“星期一Tina会见Sally和Harris。然后Tina会拜访她的妈妈Marina。Marina和Tina会见David晚餐。

我尝试了以下方法,但这击败了干本人。有没有更好的办法?

string = "Monday Tina will meet Sally and Harris. Then Tina will visit her mom Marina. Marina and Tina will meet David for dinner. Sally will then take Tina out for a late night party." 

puts "Marina appears #{string.split.count("brown").to_i} times."
puts "Tina appears #{string.split.count("grey").to_i} times."
puts "Sally appears #{string.split.count("blue").to_i} times."

预期结果:程序在文本中查找唯一的单词并将其返回。

实际:我必须在其自己的PUTS行上对每个唯一单词进行硬编码,并执行string.split.count(用于该唯一单词)

注意: 我尝试了以下内容,但这给了我每个单词。我需要对其进行优化,以使其仅满足我的要求。这就是我在努力的地方。

def cw(string)
  w = string.split(' ')
  freq = Hash.new(0)
  w.each { |w| freq[w.downcase] += 1 }
  return freq
end
puts cw(string)

2 个答案:

答案 0 :(得分:4)

def count_em(str, who)
  str.gsub(/\b(?:#{who.join('|')})\b/i).
      each_with_object(Hash.new(0)) { |person,h| h[person] += 1 }
end

str = "Monday Tina will meet Sally and Harris. Then Tina will visit her " +
      "mom Marina. Marina and Tina will meet David for dinner. Sally will " +
      "then take Tina out for a late night party." 

who = %w| Sally Marina Tina |

count_em(str, who)
  #> {"Tina"=>4, "Sally"=>2, "Marina"=>2}

第一步如下。

r = /\b(?:#{who.join('|')})\b/i
  #=> /\b(?:Sally|Marina|Tina)\b/i
enum = str.gsub(r)
  #=> #<Enumerator: "Monday Tina will meet Sally and Harris. Then
  #   ...
  #   for a late night party.":gsub(/\b(?:Sally|Marina|Tina)\b/i)>

我们可以将其转换为数组,以查看将传递给each_with_object的值。

enum.to_a
  #=> ["Tina", "Sally", "Tina", "Marina", "Marina", "Tina", "Sally", "Tina"]

然后我们只计算由enum生成的唯一值的实例数。

enum.each_with_object(Hash.new(0)) { |person,h| h[person] += 1 }
  #=> {"Tina"=>4, "Sally"=>2, "Marina"=>2}

请参见String#gsub,尤其是只有一个参数且没有任何块的情况。公认这是gsub的不寻常用法,因为它没有替代,但是在这里我更喜欢String#scan,因为gsub返回一个枚举器,而scan生成一个临时数组。

另请参见Hash::new,其中new带有参数且没有任何块。该参数称为默认值。如果h是这样定义的哈希值,则如果h[k]没有密钥h,则k返回默认值。哈希没有改变。

此处的默认值为零。解析表达式h[person] += 1时,它将转换为:

h[person] = h[person] + 1

如果person等于"Tina",并且这是枚举器首次生成"Tina"并将其传递给块,则h将没有键{{ 1}},因此表达式变为:

"Tina"

h["Tina"] = 0 + 1 是默认值。下次将0传递给该块时,该哈希具有一个密钥"Tina"(具有值"Tina"),因此将执行以下计算。

1

答案 1 :(得分:0)

仅获取所需的人员姓名:

people = ['Marina', 'Tina', 'Sally', 'Dory']
tmp = string.scan(/\w+/).keep_if{ |w| people.include? w }
counts people.map{ |name| [name, tmp.count{|n| n == name }] }.to_h
counts #=> {"Marina"=>2, "Tina"=>4, "Sally"=>2, "Dory"=>0}

这会将针对peopole的{​​{1}}数组映射到包含tmp的嵌套数组,然后转换为哈希。

好处是,如果没有人出现,它将返回[name, count],请参见0


要获取总数,可以通过两种方式:

'Dory'