ruby
35 lines · 9 steps
Building a pivot table in Ruby
Aggregate flat sales records into a region-by-quarter grid with row and column totals, then render it as tab-separated text.
Explained by
highlit
1def build_pivot_table(sales)
2 pivot = sales.each_with_object(Hash.new { |h, k| h[k] = Hash.new(0.0) }) do |record, table|
3 region = record.fetch(:region)
4 quarter = record.fetch(:quarter)
5 table[region][quarter] += record.fetch(:amount)
6 end
7
8 quarters = pivot.values.flat_map(&:keys).uniq.sort
9
10 rows = pivot.map do |region, by_quarter|
11 cells = quarters.map { |q| by_quarter[q] }
12 { region: region, cells: cells, total: cells.sum }
13 end
14
15 column_totals = quarters.each_with_index.map do |_, i|
16 rows.sum { |row| row[:cells][i] }
17 end
18
19 {
20 quarters: quarters,
21 rows: rows.sort_by { |row| -row[:total] },
22 column_totals: column_totals,
23 grand_total: column_totals.sum
24 }
25end
26
27def format_pivot(pivot)
28 header = ["Region", *pivot[:quarters], "Total"].join("\t")
29 body = pivot[:rows].map do |row|
30 [row[:region], *row[:cells].map { |c| format('%.2f', c) }, format('%.2f', row[:total])].join("\t")
31 end
32 footer = ["Total", *pivot[:column_totals].map { |c| format('%.2f', c) }, format('%.2f', pivot[:grand_total])].join("\t")
33
34 [header, *body, footer].join("\n")
35end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A Hash with a block default lets you accumulate into nested structures without pre-initializing keys.
- 2Deriving the column axis from the data keeps the table robust when records skip some quarters.
- 3Separating aggregation from formatting makes each stage independently testable and reusable.
Related explainers
ruby
require "shellwords" require "open3" module Backup
Building safe shell commands in Ruby
shell-out
subprocess
command-injection
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
ruby
class LogAggregator BUCKET_FORMAT = "%Y-%m-%dT%H:%M" def initialize(entries)
Bucketing log entries by the minute in Ruby
aggregation
hashing
enumerable
Intermediate
5 steps
ruby
class WeeklySignupsReport DEFAULT_WEEKS = 12 def initialize(weeks: DEFAULT_WEEKS, source: User.all)
Building a weekly signups report in Rails
service object
aggregation
group by
Intermediate
7 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
ruby
class ApplicationController < ActionController::Base EXPERIMENTS = { checkout_button_color: %w[control blue green], onboarding_flow: %w[control streamlined]
How A/B test cohorts are assigned in Rails
a-b-testing
cookies
hashing
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-pivot-table-in-ruby-explained-ruby-5935/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.