Ruby: Basic Enumerable Methods: Add `each_with_object`
Complete the following REQUIRED checkboxes:
- [x] I have thoroughly read and understand The Odin Project Contributing Guide
- [x] The title of this issue follows the
location for request: brief description of requestformat, e.g.NodeJS course: Add lessons on XYZ
The following checkbox is OPTIONAL:
- [ ] I would like to be assigned this issue to work on it (I am glad to do it, or support someone else to do i)
1. Description of the Feature Request:
In my perception from reading in the discord many people struggle with the reduce method. In particular with the fact that you have to return the accumulator. I believe this to partially be connected to the fact, that the lesson and the exercise use an example, where there are better enumerable methods there for the job
the lesson uses:
votes = ["Bob's Dirty Burger Shack", "St. Mark's Bistro", "Bob's Dirty Burger Shack"]
votes.reduce(Hash.new(0)) do |result, vote|
result[vote] += 1
result
end
and the exercise asks for:
def find_word_lengths(word_list)
# use #reduce to iterate through each item of the word_list (an array)
# return a hash with each word as the key and its length as the value
# hint: look at the documentation and review the reduce examples in basic enumerable lesson
end
Both of these things are actually better / more easily solved with each_with_object
```ruby
votes = ["Bob's Dirty Burger Shack", "St. Mark's Bistro", "Bob's Dirty Burger Shack"]
votes.each_with_object(Hash.new(0)) do |vote, result|
result[vote] += 1
end
One example of somebody being confused (https://discord.com/channels/505093832157691914/543074220691947531/1000686267601784852)
IMO having to return the accumulator is confusing in those cases, I consider it being a code smell. If you have a last line result in your reduce / inject, it means you probably should use each_with_object. Reduce is really for situations where you immediately want to pass the result computation to the next iteration, like you accumulator + item.
So the example given in the lesson and the exercise I think are bad examples in that sense. Therefore I suggest we introduce also each_with_object in the lesson and let people work with that instead.
What do you think? Personally it bugs me every time I see someone asking for help on that part, and my honest answer would be, don't use reduce at all, but I don't want to confuse a ruby beginner with recommendations that kinda contradict the TOP lesson.
What are your thoughts on this, I don't want to put in work into a PR unless I know that the change is welcome :-)
@RolandStuder I've thought the same thing before and I think I agree, but just to play devil's advocate:
- Reduce is a more foundational method to learn
- This use case might not be appropriate in Ruby, but it would be a use case for JS - so it's perhaps important to learn this is something you can do
- If we're gong to suggest a more appropriate method, why not got for
Enumerable#tally? - If we introduce both, they have very similar use cases but slightly different method signatures - potentially confusing
Despite all that I'm not opposed to changing it, but would be curious if you had any counter-counter points :thinking:
This issue is stale because it has had no activity for the last 30 days.
@ChargrilledChook Very good points of @ChargrilledChook I had the same thoughts before, but it bugged me. But thinking again about the context, yes I think using reduce/inject even if not the ideal method is probably a good choice.
Would each_of_object fit in an "Intermediate Enumerables" lesson perhaps? - we once had plans of introducing more enumerables somewhere in the middle of the Ruby course - https://github.com/TheOdinProject/curriculum/blob/main/archive/ruby/future_lessons/advanced_enumerables.md (ignore the "advanced" title lol)
@KevinMulhern I think that's a great idea - particularly since it's a nice way to teach the core concept / low level way, and later introduce people how to leverage the core library