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

Walkthrough

Space play step click any line
Three takeaways
  1. 1A Hash with a block default lets you accumulate into nested structures without pre-initializing keys.
  2. 2Deriving the column axis from the data keeps the table robust when records skip some quarters.
  3. 3Separating aggregation from formatting makes each stage independently testable and reusable.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a pivot table in Ruby — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code