Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
60: group_by and partition
At some point in every project, you're going to find yourself staring at a big list of objects and thinking, "I need to organize these into buckets." Maybe it's grouping orders by their shipping status or separating users into those who have verified their emails and those who haven't. Most developers start by doing this manually, and while it works, it usually results in a lot of boilerplate that obscures what you're actually trying to achieve.
The manual bucket-sorting headache
Imagine we have a list of Task objects, and each has a priority: :high, :medium, or :low. If you were approaching this naively, you'd probably initialize an empty hash and loop through your tasks, manually checking if a key exists before pushing the task into an array. It looks something like this:
tasks = [
{ name: "Fix bug", priority: :high },
{ name: "Update docs", priority: :low },
{ name: "Email client", priority: :high },
{ name: "Refactor CSS", priority: :medium }
]
grouped = {}
tasks.each do |task|
priority = task[:priority]
grouped[priority] ||= []
grouped[priority] << task
end
I've seen this pattern a thousand times. It's not "wrong"—it's logically sound—but it's noisy. You're spending three lines of code just managing the state of the hash (the ||= [] trick) rather than describing the relationship between the data and the group. When I review PRs, this is the first thing I flag, not because it's slow, but because it's mentally taxing to read. You have to simulate the loop in your head to realize, "Oh, they're just grouping by priority."
Letting Ruby handle the hash
This is exactly why group_by exists. It collapses that entire loop into a single, declarative line. Instead of telling Ruby how to build the hash, you tell it what the key should be.
grouped = tasks.group_by { |task| task[:priority] }
That's it. Ruby handles the hash initialization and the array pushing behind the scenes. The result is identical to the manual approach, but the intent is immediate. If you're grouping by a simple attribute, you can even use the shorthand symbol syntax: tasks.group_by { _1[:priority] }. I prefer this because it keeps the focus on the data structure rather than the plumbing.
When you only have two piles
Now, group_by is great for an unknown or large number of categories. But what happens when you only have two options? Say you want to split your tasks into "Urgent" (high priority) and "Not Urgent" (everything else).
A common mistake I see is developers using select twice. They'll run one select to get the urgent tasks, and then another reject (or another select with a negated condition) to get the rest. While that feels clean, you're actually iterating over your entire collection twice. If you have ten thousand items, you've just done twice the work for no reason.
You could use group_by here, but that returns a hash. If you only need two arrays, a hash is overkill and forces you to access your data via keys like grouped[true] and grouped[false], which feels clunky.
The efficiency of a single split
This is where partition comes in. Think of partition as a specialized version of group_by that specifically returns a two-element array: the first element contains everything that returned true for the block, and the second contains everything that returned false.
urgent, others = tasks.partition { |task| task[:priority] == :high }
I love this method because it combines the efficiency of a single pass with the elegance of parallel assignment. You get two distinct arrays immediately. It's much more intentional than group_by when the logic is binary. If you find yourself writing a group_by where the block returns a boolean, you should probably be using partition instead.
📋 Practical Task
Categorizing an Inventory of Out-of-Stock Items
You are managing a warehouse inventory. You have an array of product hashes, and you need to perform two specific organizational tasks for a morning report.
Given the following data:
products = [
{ name: "Mechanical Keyboard", category: :peripherals, stock: 0 },
{ name: "Gaming Mouse", category: :peripherals, stock: 5 },
{ name: "27-inch Monitor", category: :displays, stock: 0 },
{ name: "USB-C Cable", category: :accessories, stock: 12 },
{ name: "HDMI Adapter", category: :accessories, stock: 0 },
{ name: "4K Monitor", category: :displays, stock: 2 }
]
Write a script that does the following:
- Use
group_byto create a hash where the keys are the product categories and the values are arrays of products belonging to that category. - Use
partitionto split the originalproductslist into two separate arrays:out_of_stock(where stock is 0) andin_stock(where stock is greater than 0). - Print the
out_of_stockarray to verify your results.
There are no comments for now.