From abce6f2ae0f5fa36ea2069e69a4a070156644ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sat, 31 Jul 2021 22:49:00 +0200 Subject: recursive inner_sort_by --- cli/src/main.rs | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/cli/src/main.rs b/cli/src/main.rs index 12325e2..e405e48 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,6 @@ use chrono::naive::NaiveDate; use rust_decimal::Decimal; +use std::cmp::Ordering; use std::path::PathBuf; use std::str::FromStr; use structopt::clap::AppSettings; @@ -141,46 +142,44 @@ fn main() { if sort.is_empty() { transactions.sort_by_key(|t| t.date); } else { - match &sort[0] { - SortTarget::Amount => transactions.sort_by_key(|t| t.amount), - SortTarget::Date => transactions.sort_by_key(|t| t.date), - } - for i in 1..sort.len() { - //TODO This won't work with 3+ sorts in case key 2 are equal across a key 1 - // border. We need to pass the earlier buckets for later sorts as well. - // `Vec`? - inner_sort_by(&mut transactions, sort_by_func(&sort[i-1]), sort_by_func(&sort[i])); - } + let mut sorts: Vec<_> = sort.iter().map(sort_by_func).collect(); + inner_sort_by(&mut transactions, &mut sorts); } println!("{}", Table::new(transactions).with(Style::psql())); } } } -fn sort_by_func(sort: &SortTarget) -> impl FnMut(&&Transaction, &&Transaction) -> std::cmp::Ordering { +fn sort_by_func(sort: &SortTarget) -> impl FnMut(&&Transaction, &&Transaction) -> Ordering { match sort { SortTarget::Amount => |t1: &&Transaction, t2: &&Transaction| t1.amount.cmp(&t2.amount), SortTarget::Date => |t1: &&Transaction, t2: &&Transaction| t1.date.cmp(&t2.date), } } -fn inner_sort_by(v: &mut [T], mut outer_cmp: F, mut inner_cmp: F) +fn inner_sort_by(v: &mut [T], cmps: &mut [F]) where - F: FnMut(&T, &T) -> std::cmp::Ordering, + F: FnMut(&T, &T) -> Ordering, { // Early out - if v.len() < 2 { + if v.len() < 2 || cmps.is_empty() { return; } + v.sort_by(&mut cmps[0]); + + let mut ranges = Vec::new(); let mut lower = 0; // Lower bound of current equal range for i in 0..v.len() { - if outer_cmp(&v[i], &v[lower]) != std::cmp::Ordering::Equal { - let upper = i; - if upper - lower > 1 { - v[lower..upper].sort_by(&mut inner_cmp); - } + if cmps[0](&v[i], &v[lower]) != Ordering::Equal { + ranges.push(lower..i); lower = i; } } + + if cmps.len() != 1 { + for range in ranges { + inner_sort_by(&mut v[range], &mut cmps[1..]); + } + } } -- cgit v1.2.1