This chapter explores Ruby Enumerables, a powerful module that provides a collection of iteration and search methods for classes that include it. Enumerables allow for concise and expressive code when working with collections like arrays, hashes, and ranges.
Chapter Goals
- Understand the purpose and usage of the Enumerable module in Ruby.
- Learn about common enumerable methods such as map, select, reject, and reduce.
- Explore how to implement custom enumerables by including the Enumerable module.
- Implement best practices for leveraging enumerables effectively in Ruby.
Key Characteristics of Ruby Enumerables
- Iterative Methods: Provide a variety of methods for traversing and manipulating collections.
- Chained Operations: Methods can be chained for expressive and concise code.
- Custom Enumerables: Allows the creation of custom classes with enumerable functionality.
- Consistency: Follows a unified approach across different collection types.
Basic Rules for Enumerables
- Use include Enumerable in a class to gain access to enumerable methods.
- Define an each method in the class to make it compatible with Enumerable.
- Use built-in enumerable methods to simplify iteration and manipulation tasks.
Best Practices
- Use descriptive variable names in enumerable blocks for clarity.
- Combine enumerable methods to write concise and expressive code.
- Prefer enumerables over manual loops for better readability and maintainability.
- Avoid chaining too many methods in a single expression to maintain readability.
- Document non-trivial enumerable logic for maintainability.
Syntax Table
Serial No | Method | Syntax/Example | Description | ||
1 | map | `collection.map { | item | code }` | Transforms each element and returns a new collection. |
2 | select | `collection.select { | item | condition }` | Returns elements that match the condition. |
3 | reject | `collection.reject { | item | condition }` | Returns elements that do not match the condition. |
4 | reduce (or inject) | `collection.reduce(initial) { | memo, item | code }` | Combines all elements into a single value. |
5 | any? | `collection.any? { | item | condition }` | Returns true if any element matches the condition. |
6 | all? | `collection.all? { | item | condition }` | Returns true if all elements match the condition. |
7 | none? | `collection.none? { | item | condition }` | Returns true if no elements match the condition. |
Syntax Explanation
1. map
What is map?
The map method transforms each element in a collection and returns a new collection.
Syntax
collection.map { |item| code }
Detailed Explanation
- Applies the block to each element of the collection.
- Returns a new collection with transformed elements.
- Non-destructive: does not modify the original collection.
Example
numbers = [1, 2, 3]
squares = numbers.map { |n| n ** 2 }
puts squares
Example Explanation
- Transforms [1, 2, 3] into [1, 4, 9] by squaring each number.
2. select
What is select?
The select method returns elements that match a specified condition.
Syntax
collection.select { |item| condition }
Detailed Explanation
- Filters elements based on the block’s condition.
- Returns a new collection containing only matching elements.
Example
numbers = [1, 2, 3, 4, 5]
even_numbers = numbers.select { |n| n.even? }
puts even_numbers
Example Explanation
- Filters [1, 2, 3, 4, 5] to include only even numbers, resulting in [2, 4].
3. reject
What is reject?
The reject method returns elements that do not match a specified condition.
Syntax
collection.reject { |item| condition }
Detailed Explanation
- Filters out elements based on the block’s condition.
- Returns a new collection without the rejected elements.
Example
numbers = [1, 2, 3, 4, 5]
odd_numbers = numbers.reject { |n| n.even? }
puts odd_numbers
Example Explanation
- Filters [1, 2, 3, 4, 5] to exclude even numbers, resulting in [1, 3, 5].
4. reduce (or inject)
What is reduce?
The reduce method combines all elements in a collection into a single value.
Syntax
collection.reduce(initial) { |memo, item| code }
Detailed Explanation
- Takes an initial value and applies the block to combine elements iteratively.
- Returns the final combined value.
Example
numbers = [1, 2, 3, 4]
sum = numbers.reduce(0) { |sum, n| sum + n }
puts sum
Example Explanation
- Combines [1, 2, 3, 4] to calculate the sum, resulting in 10.
5. Custom Enumerables
How to Create Custom Enumerables?
Include the Enumerable module in a class and define the each method.
Syntax
class CustomCollection
include Enumerable
def initialize(items)
@items = items
end
def each(&block)
@items.each(&block)
end
end
collection = CustomCollection.new([1, 2, 3])
puts collection.map { |n| n ** 2 }
Example Explanation
- Defines a custom collection that includes Enumerable and implements each.
- Allows the use of enumerable methods like map on the custom collection.
Real-Life Project
Project Name: Filtered Product List
Project Goal
Create a program to filter and process a list of products using enumerable methods.
Code for This Project
products = [
{ name: "Laptop", price: 1000 },
{ name: "Mouse", price: 50 },
{ name: "Keyboard", price: 70 },
{ name: "Monitor", price: 200 }
]
# Filter products under $100
affordable = products.select { |product| product[:price] < 100 }
# Map to product names
names = affordable.map { |product| product[:name] }
puts "Affordable products: \#{names.join(", ")}"
Steps
- Define a list of products as an array of hashes.
- Use select to filter products based on price.
- Use map to extract product names from the filtered list.
- Display the filtered product names.
Expected Output
Affordable products: Mouse, Keyboard
Project Explanation
- Demonstrates filtering and transforming data using enumerable methods.
- Highlights the expressiveness and power of Ruby enumerables.
Insights
Ruby enumerables provide a robust set of tools for working with collections. Understanding their usage enables developers to write concise, expressive, and maintainable code.
Key Takeaways
- Use map, select, and reject for common collection transformations and filters.
- Leverage reduce for combining elements into a single value.
- Create custom enumerables by including the Enumerable module and defining each.
- Write clear and expressive enumerable logic for improved readability and maintainability.