Rust Iterator Pipeline for Order Reports
Chain Rust iterators to filter refunded orders, fold totals, group revenue by customer, and rank the top accounts without extra crates.
Code
use std::collections::BTreeMap;
#[derive(Debug, Clone)]
struct Order {
id: u32,
customer: String,
cents: u64,
refunded: bool,
}
fn main() {
let orders = vec![
Order { id: 1, customer: "ada".to_string(), cents: 4_500, refunded: false },
Order { id: 2, customer: "lin".to_string(), cents: 2_300, refunded: false },
Order { id: 3, customer: "ada".to_string(), cents: 9_900, refunded: true },
Order { id: 4, customer: "ada".to_string(), cents: 1_200, refunded: false },
Order { id: 5, customer: "sam".to_string(), cents: 7_500, refunded: false },
];
let paid: Vec<&Order> = orders.iter().filter(|order| !order.refunded).collect();
let net_cents: u64 = paid.iter().map(|order| order.cents).sum();
let (count, total) = paid
.iter()
.fold((0usize, 0u64), |(count, total), order| {
(count + 1, total + order.cents)
});
let average_cents = total as f64 / count as f64;
let mut by_customer: BTreeMap<&str, u64> = BTreeMap::new();
for order in &paid {
*by_customer.entry(order.customer.as_str()).or_insert(0) += order.cents;
}
let mut ranked: Vec<(&str, u64)> = by_customer.into_iter().collect();
ranked.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(b.0)));
let top: Vec<String> = ranked
.iter()
.take(2)
.enumerate()
.map(|(index, (customer, cents))| format!("{}. {customer}: {cents} cents", index + 1))
.collect();
let refunded_ids: Vec<u32> = orders
.iter()
.filter(|order| order.refunded)
.map(|order| order.id)
.collect();
println!("paid orders: {count}, net: {net_cents} cents, average: {average_cents:.2} cents");
println!("top customers: {top:?}");
println!("refunded order ids: {refunded_ids:?}");
}Report a problem with this exampleOpens a pre-filled issue on GitHub.