2

I'm new to Ruby (and coding in general) and trying to convert an array into a hash, with keys being words and values being the number of times the words occur in the array (so e.g. "banana" => 1, "mango" => 2 etc).

I'm trying to do so with each_with_object as I read it should work for building new hashes from arrays.

array = %w(banana pear mango kiwi mango)

hash1 = array.each_with_object(Hash.new(0)) do |word, count|
  hash1[word] = count
  count += 1
  return hash1
end

puts hash1

But the code doesn't work at all. Can someone please explain to me why not and what I should change?

Thank you!

3
  • 1
    Possible duplicate of Ruby: How to group a Ruby array? Commented Apr 8, 2019 at 19:37
  • 2
    Read about the use of return in a block. Try hash[word] += 1 just with word and hash as block variables. Commented Apr 8, 2019 at 19:44
  • "doesn't work at all" is not a precise enough error description for us to help you. What doesn't work? How doesn't it work? What trouble do you have with your code? Do you get an error message? What is the error message? Is the result you are getting not the result you are expecting? What result do you expect and why, what is the result you are getting and how do the two differ? Is the behavior you are observing not the desired behavior? What is the desired behavior and why, what is the observed behavior, and in what way do they differ? Commented Apr 9, 2019 at 9:09

5 Answers 5

3

To make your code work you would need to fix the way you use each_with_object.

array = %w(banana pear mango kiwi mango)

hash1 = array.each_with_object(Hash.new(0)) do |word, counts|
  counts[word] += 1
end

puts hash1

Hash.new(0) is a hash that returns zero when an unknown key is read. So what you're doing here is populating it by iterating over array and increasing the count for each key by one.

I recommend reading more up on reduce and each_with_object to understand their usage.

Fabio's answer is the more idiomatic one, but I just wanted to show how to fix your code rather than rewrite it.

Sign up to request clarification or add additional context in comments.

3 Comments

I think this is the best way to do it.
Thanks, this is really helpful. But why do we write counts[word] +=1 rather than word[counts] +=1 ? I think the fact that "count", which is the value, goes before the "word", which is the key, confuses me. Is it because "word" here is a key so it has to be in []?
counts here is a hash (Hash.new(0)) where the keys are strings and the values are numbers. This is the signature of each_with_object. Maybe add a puts counts in the loop so you can see. You could rename counts to hash if that makes things more clear for you
2

With latest ruby (itself and transform_values methods) you can do:

%w(word one two word).group_by(&:itself).transform_values(&:length)
# => {"word"=>2, "one"=>1, "two"=>1}

Where

.group_by(&:itself)
# returns => {"word"=>["word", "word"], "one"=>["one"], "two"=>["two"]}

.transform_values(&:length)
# returns => {"word"=>2, "one"=>1, "two"=>1}

Comments

1

Don't know if its efficient way or not, but its alternate way %w[banana pear mango kiwi mango].group_by{|x| x}.map{|key, values| [key, values.length]}.to_h

Comments

1

While you can follow the comments above for fixing your code, I liked to provide this alternative:

array.zip.group_by(&:first).transform_values(&:size)
#=> {"banana"=>1, "pear"=>1, "mango"=>2, "kiwi"=>1}

Comments

0

Since Ruby 2.7 there is the tally method. Here is the code example:

%w(banana pear mango kiwi mango).tally

output:

{"banana"=>1, "pear"=>1, "mango"=>2, "kiwi"=>1}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.