diff --git a/src/move_money.rs b/src/move_money.rs index 451320c..6396e6c 100644 --- a/src/move_money.rs +++ b/src/move_money.rs @@ -91,7 +91,16 @@ pub struct CsvCost { pub department: String, #[serde(serialize_with = "round_serialize")] pub value: f64, - pub pass: Option, +} + +#[derive(Serialize)] +pub struct MovedMoneyAmount { + pub account: String, + pub department: String, + pub value: f64, + pub from_account: String, + pub from_department: String, + pub pass: i32, } fn round_serialize(x: &f64, s: S) -> Result @@ -271,16 +280,15 @@ where } // Then run move_money - let moved = move_money_2(lines, &rules, flush_pass); + let moved = move_money_2(lines, &rules, flush_pass, output); - // Ouput the list moved moneys - for money in moved { - for (unit, value) in money.totals { + if !flush_pass { + // Ouput the final moneys + for (unit, value) in moved { output.serialize(CsvCost { account: unit.account, department: unit.department, value, - pass: if flush_pass { Some(money.pass) } else { None }, })?; } } @@ -323,12 +331,6 @@ fn extract_range(from: String, to: String, options: &Vec) -> HashSet, -} - // Approach 2: // Traditinoal/naive, total for each department is stored in an initial map (department -> total amount). // Another map is built up for each rule, and each rule is processed based on the amount in the current total @@ -340,41 +342,39 @@ pub struct MoveMoneyResult { // to every. It's also much more memory efficient than approach 1. // TODO: Time both approaches to seee which is faster depending on the size of the input data/number of rules // Verdict: This is already pretty fast, at least much faster than ppm for BigDataset -pub fn move_money_2( +pub fn move_money_2( initial_totals: HashMap, rules: &Vec, flush_pass: bool, -) -> Vec { + output: &mut csv::Writer, +) -> HashMap +where + W: std::io::Write, +{ // Note: It's potentially a bit more intensive to use cloned totals (rather than just update temp_total per rule), // but it's much simpler code and, and since we're only working line-by-line, it isn't really that much memory in practice // TODO: This is initial totals is problematic, as we may move into a cc that wasn't in the list of lines. In which case we'd need // to add a new line let mut running_total = HashMap::from(initial_totals); let mut temp_total = running_total.clone(); - let mut move_money_result: Vec = vec![]; let mut current_pass = 0; if flush_pass { - move_money_result.push(MoveMoneyResult { - pass: current_pass, - totals: running_total.clone(), - }) + for (unit, value) in running_total.iter() { + output + .serialize(MovedMoneyAmount { + account: unit.account.clone(), + department: unit.department.clone(), + value: *value, + from_account: unit.account.clone(), + from_department: unit.department.clone(), + pass: current_pass, + }) + .expect("Failed to write moved amount") + } } for rule in rules { if rule.is_separator { - if flush_pass { - current_pass += 1; - // Flush the totals at the end of this pass (more specifically the change) - move_money_result.push(MoveMoneyResult { - pass: current_pass, - totals: temp_total - .iter() - .map(|(unit, value)| { - (unit.clone(), value - running_total.get(unit).unwrap_or(&0.)) - }) - .filter(|(_, value)| *value != 0.) - .collect(), - }); - } + current_pass += 1; running_total = temp_total.clone(); } else { for (unit, amount) in &running_total { @@ -399,6 +399,18 @@ pub fn move_money_2( } else { unit.account.clone() }; + if flush_pass { + output + .serialize(MovedMoneyAmount { + department: department.clone(), + account: department.clone(), + value: added_amount, + from_department: unit.department.clone(), + from_account: unit.account.clone(), + pass: current_pass, + }) + .expect("Failed to write moved amount"); + } *temp_total .entry(Unit { department, @@ -409,12 +421,7 @@ pub fn move_money_2( } } } - move_money_result.push(MoveMoneyResult { - pass: current_pass, - totals: temp_total, - }); - - move_money_result + temp_total } #[cfg(test)] diff --git a/src/overhead_allocation.rs b/src/overhead_allocation.rs index 53c6972..9754661 100644 --- a/src/overhead_allocation.rs +++ b/src/overhead_allocation.rs @@ -381,7 +381,6 @@ where account: cost.account.clone(), department: department.department, value: department.value, - pass: None, })?; } }