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
202: Processing Large CSV Files Efficiently
Imagine you’re tasked with auditing a massive physical archive of records—say, ten thousand thick ledger books filling an entire warehouse. You have two ways to approach this. You could try to carry every single book back to your desk at once, piling them up until the desk collapses under the weight. Or, you could walk to the shelf, pull out one book, record the data you need, put it back, and move to the next one.
In Ruby, CSV.read is the equivalent of trying to carry the whole warehouse to your desk. It loads the entire file into your RAM (your "desk"). If the file is 50MB, you're probably fine. If it's 5GB, your application will freeze, the OS will start swapping to disk, and eventually, your process will crash with a "NoMemoryError". CSV.foreach, on the other hand, is the act of processing one row at a time. It keeps your memory footprint tiny, regardless of whether the file has ten rows or ten million.
The Memory Trap: Why CSV.read will kill your server
I've seen junior devs use CSV.read because it's convenient; it gives you an array of arrays that you can map, filter, and sort immediately. It feels like working with a standard Ruby array. But in production, that's a ticking time bomb. When you call CSV.read("large_data.csv"), Ruby allocates memory for every single string in every single cell of that file simultaneously.
If you're processing a file of e-commerce transactions to calculate total revenue, you don't actually need the 1st row and the 1,000,000th row in memory at the same time. You just need the current row's price, then you add it to a running total and move on.
Streaming with CSV.foreach
The foreach method is an iterator. It opens the file, reads one line, yields that line to the block, and then clears that line from memory to make room for the next one. Here is how I would handle a massive sales export:
require 'csv'
total_revenue = 0
# This doesn't load the file into RAM; it streams it.
CSV.foreach("massive_sales_export.csv", headers: true) do |row|
# 'row' is a CSV::Row object, which acts like a hash
total_revenue += row["price"].to_f
end
puts "Total Revenue: #{total_revenue}"
Notice how the memory usage stays flat throughout the entire process. Whether that file is 1MB or 10GB, your script will use roughly the same amount of RAM.
Trimming the Fat with Headers and Converters
When you're dealing with huge files, you want to spend as little time as possible transforming data inside the loop. Calling .to_f or .to_i on every single iteration is tedious and slightly slower. Ruby's CSV library has a built-in way to handle this via converters.
If you tell Ruby to use the :numeric converter, it will automatically attempt to convert any value that looks like a number into an Integer or Float before it even hits your block. I usually pair this with headers: true so I can access data by column name instead of counting indices (which is a nightmare to maintain when the CSV layout changes).
require 'csv'
# Using converters: :numeric saves us from manual .to_f calls
CSV.foreach("massive_sales_export.csv", headers: true, converters: :numeric) do |row|
# row["price"] is already a Float here
puts "Processing transaction #{row["transaction_id"]}..." if row["price"] > 1000
end
One last pro tip: if you're dealing with a file that's truly gargantuan and has weird encoding issues (which CSVs always do), add encoding: 'UTF-8' or invalid: :replace to your options. It'll save you from the dreaded Encoding::InvalidByteSequenceError halfway through a three-hour processing job.
📋 Practical Task
The Million-Dollar Transaction Analyzer
You have been given a CSV file named transactions.csv containing 100,000 rows of sales data. Each row has the following columns: transaction_id, category, amount, and date.
Your goal is to write a Ruby script that calculates two things without loading the entire file into memory:
- The Grand Total of all transaction amounts.
- The Most Frequent Category (the category that appears most often).
Requirements:
- Use
CSV.foreachto ensure memory efficiency. - Use
headers: trueto access columns by name. - Use
converters: :numericto handle the amount conversion automatically. - Use a Hash to track the counts of each category as you iterate through the file.
There are no comments for now.