I new to Ruby and struggling to understand what is going on in this bit of code I wrote. Why do I have to declare two variables |x,y| to get the output I am expecting? I am only using x and y always appears to be nil. But when I change to |x|, my word count is always 0 (see code and output below). Thanks for any insight you may be able to provide.
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}
The other answer correctly explains why this doesn’t work as expected. Let me try to point out some more problems with your code:
string.downcase!modifies the argument given to the function, which is extremely bad style/(\b\w+\b)/you don’t need an additional match group here, simply use/\b\w+\b/. This will allow you to just usescan(...) do |x|, wherexwill be the matched wordwordhash.store(x,y)can simply be written aswordhash[x] = ystring.scan(/\b#{x}\b/).lengthyou scan the string a second time, although that is not necessary. Instead, you can just increment a counter for every match of a given word.Example:
This is just to demonstrate how your approach could be made working, in Ruby you’d probably solve this in a more functional way, preferrably using
group_by, as Michael already demonstrated or usinginject: