我是Ruby的新手,并且正在努力理解我编写的这段代码中发生了什么。为什么我必须声明两个变量|x,y|
来获得我期望的输出?我只使用x
而y
似乎总是nil
。但是当我更改为|x|
时,我的字数始终为0
(请参阅下面的代码和输出)。感谢您提供的任何见解。
def count_words(string)
string.downcase!
wordhash = Hash.new
# what is going on here?
# Why do I have to have two
# variables in the scan block?
string.scan(/(\b\w+\b)/){|x,y|
wordhash.store(x,string.scan(/\b#{x}\b/).length)}
return wordhash
end
puts count_words("Hello there. This is bob bob bob")
# Correct Output with |x,y|:
# {"hello"=>1, "there"=>1, "this"=>1, "is"=>1, "bob"=>3}
# Incorrect Output with |x|:
# {["hello"]=>0, ["there"]=>0, ["this"]=>0, ["is"]=>0, ["bob"]=>0}
答案 0 :(得分:3)
来自String#scan
文档:
如果模式包含组,则每个结果本身都是一个 每个组包含一个条目的数组。
由于您的模式包含一个组,因此第一个块参数是一个数组。如果您使用|x, y|
,则会对数组进行解构并将其第一个元素指定给x
。
顺便说一句,要获得字数统计,你可以这样做:
s = "this is a test string it is"
Hash[s.split.group_by{ |e| e }.map { |k,v| [k, v.size] }]
#=> {"this"=>1, "is"=>2, "a"=>1, "test"=>1, "string"=>1, "it"=>1}
答案 1 :(得分:2)
另一个答案正确地解释了为什么这不能按预期工作。让我试着指出代码中的一些问题:
string.downcase!
修改赋予函数的参数,这是非常糟糕的样式/(\b\w+\b)/
您在此处不需要其他匹配组,只需使用/\b\w+\b/
即可。这样您就可以使用scan(...) do |x|
,其中x
将是匹配的字词wordhash.store(x,y)
可以简单地写成wordhash[x] = y
string.scan(/\b#{x}\b/).length
你第二次扫描字符串,虽然没有必要。相反,您可以为给定单词的每个匹配增加一个计数器。示例:
def count_words(string)
# set up a hash that accumulates the number of occurrences per word
wordcount = Hash.new(0)
string.downcase.scan(/\b\w+\b/) { |word| wordcount[word] += 1 }
# no need to use return here, the function already evaluates to the last
# value
wordcount
end
p count_words("Hello there. This is bob bob bob")
# => {"hello"=>1, "there"=>1, "this"=>1, "is"=>1, "bob"=>3}
这只是为了演示你的方法是如何工作的,在Ruby中你可能会以更实用的方式解决这个问题,最好使用group_by
,正如迈克尔已经证明或使用inject
:
string.downcase.split.inject(Hash.new(0)) { |h,word| h[word] += 1; h }