尝试编写一个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)
答案 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'