diff --git a/2018/src/common.rs b/2018/src/common.rs index 8619749..1e8f200 100644 --- a/2018/src/common.rs +++ b/2018/src/common.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; +use std::hash::Hash; use std::io; /// Apply Erathostenes's sieve to the supplied array @@ -7,7 +9,7 @@ use std::io; /// * `dest` - the destination slice to fill with the sieve. This is /// assumed to be filled with "true" before being handed to this /// method. -pub fn prime_sieve(dest: &mut[bool]) { +pub fn prime_sieve(dest: &mut [bool]) { if dest.len() >= 1 { dest[0] = false; } @@ -20,7 +22,7 @@ pub fn prime_sieve(dest: &mut[bool]) { for i in 1..(limit + 1) { if !dest[i] { - continue + continue; } for j in ((i * i)..(dest.len())).step_by(i) { @@ -48,6 +50,35 @@ pub fn trim_back(input: &mut Vec) { } } + +/// An interface to count elements in particular categories. +pub trait GroupingCount { + /// The type of the categories under inspection + type Type; + + /// Count the occurrence of all possible values. + /// + /// This method will return a map from a value to its occurrence rate. + fn grouping_count(&mut self) -> HashMap; +} + +impl GroupingCount for T + where T: Iterator, + T::Item: Eq + Hash { + type Type = T::Item; + + fn grouping_count(&mut self) -> HashMap + { + let mut counts = HashMap::new(); + + for element in self { + *counts.entry(element).or_insert(0) += 1; + } + + counts + } +} + /// Solution trait /// /// Every day's solution should implement this function so that it can @@ -79,4 +110,12 @@ mod tests { assert_eq!(output, input); } + + #[test] + fn test_grouping_count() { + let result = [1, 1, 2, 2, 3, 1].iter().grouping_count(); + assert_eq!(3, result[&1]); + assert_eq!(2, result[&2]); + assert_eq!(1, result[&3]); + } } diff --git a/2018/src/day02.rs b/2018/src/day02.rs index 2bede47..7e852eb 100644 --- a/2018/src/day02.rs +++ b/2018/src/day02.rs @@ -3,16 +3,11 @@ use std::io; use std::io::prelude::*; use common; +use common::GroupingCount; /// Count the occurrence characters in a string. -fn count_chars(word: &str) -> HashMap { - let mut counts: HashMap = HashMap::new(); - - for c in word.chars() { - *counts.entry(c).or_insert(0) += 1; - } - - counts +fn count_chars(word: &str) -> HashMap { + word.chars().grouping_count() } /// Compute the number of different positions between two strings. diff --git a/2018/src/day03.rs b/2018/src/day03.rs index a9f224f..4a9de32 100644 --- a/2018/src/day03.rs +++ b/2018/src/day03.rs @@ -3,9 +3,11 @@ use std::io; use std::io::BufRead; use std::ops::Range; -use common; use regex; +use common; +use common::GroupingCount; + #[derive(Copy, Clone, Debug)] struct Claim { x: usize, @@ -60,15 +62,10 @@ impl Day03 { } } - fn get_claims(&self) -> HashMap<(usize, usize), i32> { - let mut claims = HashMap::new(); - for claim in &self.claims { - for coordinate in claim.range() { - *claims.entry(coordinate).or_insert(0) += 1; - } - } - - claims + fn get_claims(&self) -> HashMap<(usize, usize), usize> { + self.claims.iter() + .flat_map(|x| x.range()) + .grouping_count() } } diff --git a/2018/src/day06.rs b/2018/src/day06.rs index e5640ee..b2b0036 100644 --- a/2018/src/day06.rs +++ b/2018/src/day06.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; use std::collections::HashSet; use std::io::BufRead; use std::io::BufReader; use std::io::Read; use common::Solution; +use common::GroupingCount; #[derive(Copy, Clone, Debug)] struct Coordinate { @@ -124,13 +124,9 @@ impl Solution for Day06 { infinite.extend([grid[y][0], grid[y][self.xmax]].iter().filter_map(claim_filter)); } - let mut counts = HashMap::new(); - - for instance in grid.iter().flat_map(|x| x.iter()) + let counts = grid.iter().flat_map(|x| x.iter()) .filter_map(claim_filter) - .filter(|x| !infinite.contains(x)) { - *counts.entry(instance).or_insert(0) += 1; - } + .filter(|x| !infinite.contains(x)).grouping_count(); format!("{}", counts.values().max().unwrap()) }