use std::collections::HashMap; use std::error::Error; use std::fs::File; use std::io::Read; use std::time::{Duration, UNIX_EPOCH}; fn parse( file: File, ) -> Result>, Box> { let mut file = file; let mut contents = String::new(); file.read_to_string(&mut contents)?; let mut metrics: HashMap>> = HashMap::new(); for line in contents.lines() { let re = regex::Regex::new(r"(\d+) (\w+) (\d+)").unwrap(); if let Some(caps) = re.captures(line) { let timestamp_raw = &caps[1]; let metric_name = &caps[2]; let metric_value_raw = &caps[3]; let timestamp = timestamp_raw.parse::().unwrap(); let metric_value = metric_value_raw.parse::().unwrap(); if !metrics.contains_key(metric_name) { metrics.insert(metric_name.to_string(), HashMap::new()); } let minute = UNIX_EPOCH + Duration::from_secs((timestamp - (timestamp % 60)) as u64); metrics .get_mut(metric_name) .unwrap() .insert(minute, vec![metric_value]); } else { println!("invalid line"); } } let mut aggregated_metrics: HashMap> = HashMap::new(); for (metric_name, time_val_list) in metrics { aggregated_metrics.insert(metric_name.clone(), HashMap::new()); for (time, values) in time_val_list { let mut sum = 0.0; for v in values.iter() { sum += *v } let average = sum / values.len() as f64; aggregated_metrics .get_mut(&metric_name) .unwrap() .insert(time, average); } } Ok(aggregated_metrics) } fn main() { let file = File::open("input.txt").expect("Unable to open file"); let metrics = parse(file).expect("Unable to parse file"); for (metric_name, time_val) in metrics { for (time, value) in time_val { println!( "{} {:?} {:.2}", metric_name, chrono::DateTime::::from(time), value ); } } }