Coding problem · Easy · Data Processing
Revenue Report from CSV
Easy Practical tasks Seen at Shopify, Stripe, Square
Finance sends you an orders export:
order_id,region,amount_cents,status
1001,EU,2599,paid
1002,US,1000,refunded
Return total paid revenue in cents per region as an object/map {region: cents}.
- The first line is the header; columns are always in this order.
- Trim whitespace around fields;
statusis case-insensitive (PAIDcounts). - Skip malformed rows: wrong number of columns, or an
amount_centsthat isn't a whole number. - Ignore empty lines. Regions with no paid orders are omitted.
Example 1
Input: csv = "order_id,region,amount_cents,status\n1,EU,2599,paid\n2,US,1000,refunded\n3,EU,401,PAID"
Output: {"EU":3000}
Hints
Hint 1
Split into lines, skip the header, split each row on commas, validate, then accumulate in a map.
Hint 2
Work in integer cents — never floats for money.
Write and run your solution
Loading the editor… (JavaScript is required to run code in your browser.)
Solution and explanation
Show the solution
Time O(size of input) · Space O(regions)
Line-oriented parsing with validation at each step, accumulating integers per region. Negative amounts are valid whole numbers (e.g. adjustments), which is why -200 is summed; 10.5 is rejected because cents must be integers.
Real CSV has quoted fields with embedded commas and newlines — in production use the platform CSV parser (csv in Python, fgetcsv/SplFileObject in PHP, a library in Node/Java) and stream large files row by row.
Reference solution
function revenueByRegion(csv) {
const totals = {};
for (const line of csv.split("\n").slice(1)) {
if (!line.trim()) continue;
const fields = line.split(",").map((f) => f.trim());
if (fields.length !== 4) continue;
const [, region, amount, status] = fields;
if (!/^-?\d+$/.test(amount) || status.toLowerCase() !== "paid") continue;
totals[region] = (totals[region] ?? 0) + Number(amount);
}
return totals;
}
function revenueByRegion(csv: string): Record<string, number> {
const totals: Record<string, number> = {};
const rows = csv.split("\n").slice(1).filter((l) => l.trim() !== "");
for (const row of rows) {
const fields = row.split(",").map((f) => f.trim());
if (fields.length !== 4) continue;
const [, region, amount, status] = fields;
if (!/^-?\d+$/.test(amount) || status.toLowerCase() !== "paid") continue;
totals[region] = (totals[region] ?? 0) + Number(amount);
}
return totals;
}
import re
def revenue_by_region(csv: str) -> dict[str, int]:
totals: dict[str, int] = {}
for line in csv.split("\n")[1:]:
if not line.strip():
continue
fields = [f.strip() for f in line.split(",")]
if len(fields) != 4:
continue
_, region, amount, status = fields
if not re.fullmatch(r"-?\d+", amount) or status.lower() != "paid":
continue
totals[region] = totals.get(region, 0) + int(amount)
return totals
<?php
function revenueByRegion(string $csv): array
{
$totals = [];
foreach (array_slice(explode("\n", $csv), 1) as $line) {
if (trim($line) === '') {
continue;
}
$fields = array_map('trim', explode(',', $line));
if (count($fields) !== 4) {
continue;
}
[, $region, $amount, $status] = $fields;
if (!preg_match('/^-?\d+$/', $amount) || strtolower($status) !== 'paid') {
continue;
}
$totals[$region] = ($totals[$region] ?? 0) + (int) $amount;
}
return $totals;
}
class Solution {
public Map<String, Integer> revenueByRegion(String csv) {
Map<String, Integer> totals = new HashMap<>();
String[] lines = csv.split("\n");
for (int i = 1; i < lines.length; i++) {
if (lines[i].isBlank()) continue;
String[] f = lines[i].split(",", -1);
if (f.length != 4) continue;
String region = f[1].trim(), amount = f[2].trim(), status = f[3].trim();
if (!amount.matches("-?\\d+") || !status.equalsIgnoreCase("paid")) continue;
totals.merge(region, Integer.parseInt(amount), Integer::sum);
}
return totals;
}
}
Common mistakes
- Parsing money with floats.
parseInt("10.5")→ 10 in JavaScript — validate with a regex instead.- Hand-splitting quoted CSV in production code.
Follow-up questions
- Support quoted fields.
- Stream a 5 GB file.
- Convert currencies using a rates table.
More Data Processing problems
- Top Endpoints from Access Logs · Medium
- Group Events into Sessions · Easy
- Flatten Nested JSON · Medium