From 5ee750ce96b65294c391c84d2ca7187e1f27fa07 Mon Sep 17 00:00:00 2001 From: Rohan Poojary Date: Tue, 27 Jun 2023 14:11:10 +0530 Subject: [PATCH] Add average functionality (#4) --- src/iter/average.rs | 18 ++++++++++++ src/iter/m_distinct.rs | 28 ++++++++---------- src/iter/m_enumerable.rs | 61 ++++++++++++++++++++++----------------- src/iter/m_union.rs | 49 ++++++++++++++----------------- src/iter/mod.rs | 7 +++-- src/lib.rs | 2 +- src/tests/iter_expr.rs | 6 ++-- src/tests/iter_methods.rs | 15 ++++++++-- src/tests/mod.rs | 3 +- tests/int_test.rs | 3 +- 10 files changed, 108 insertions(+), 84 deletions(-) create mode 100644 src/iter/average.rs diff --git a/src/iter/average.rs b/src/iter/average.rs new file mode 100644 index 0000000..733d39a --- /dev/null +++ b/src/iter/average.rs @@ -0,0 +1,18 @@ +pub trait Average: Sized { + fn average>(iter: I) -> Self; +} + +macro_rules! average_for_types { + ( $( $x:ident ),* ) => {$( + impl Average for $x { + fn average>(iter: I) -> Self { + let sums = iter + .enumerate() + .fold((0, Self::default()), |acc, v| (acc.0 + 1, acc.1 + v.1)); + sums.1 / (sums.0 as $x) + } + } + )*} +} + +average_for_types!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, f32, f64); diff --git a/src/iter/m_distinct.rs b/src/iter/m_distinct.rs index 48bc3a0..fc20878 100644 --- a/src/iter/m_distinct.rs +++ b/src/iter/m_distinct.rs @@ -1,17 +1,17 @@ #[derive(Clone)] pub struct DistinctIterator where - I::Item : Eq + std::hash::Hash + Copy, - I : Iterator + I::Item: Eq + std::hash::Hash + Copy, + I: Iterator, { - source : I, - hash_map : std::collections::HashSet + source: I, + hash_map: std::collections::HashSet, } impl Iterator for DistinctIterator where - I : Iterator, - I::Item : Eq + std::hash::Hash + Copy, + I: Iterator, + I::Item: Eq + std::hash::Hash + Copy, { type Item = I::Item; @@ -19,8 +19,7 @@ where loop { match self.source.next() { Some(item) => { - if self.hash_map.insert(item) - { + if self.hash_map.insert(item) { return Some(item); } } @@ -32,17 +31,14 @@ where } } - -pub fn distinct( - iter: I -) -> DistinctIterator +pub fn distinct(iter: I) -> DistinctIterator where - I : Iterator, - I::Item : Eq + std::hash::Hash + Copy, + I: Iterator, + I::Item: Eq + std::hash::Hash + Copy, { let hash_map = std::collections::HashSet::new(); DistinctIterator { - hash_map : hash_map, - source : iter + hash_map: hash_map, + source: iter, } } diff --git a/src/iter/m_enumerable.rs b/src/iter/m_enumerable.rs index 0c2f351..7250297 100644 --- a/src/iter/m_enumerable.rs +++ b/src/iter/m_enumerable.rs @@ -1,4 +1,4 @@ -use super::{m_builtin, m_method, m_order_by, m_select, m_distinct, m_union}; +use super::{average::Average, m_builtin, m_distinct, m_method, m_order_by, m_select, m_union}; use m_builtin::{ConcateIterator, ReverseIterator, SelectIterator, WhereIterator}; use m_order_by::OrderedIterator; use m_select::{SelectManyIterator, SelectManySingleIterator}; @@ -166,12 +166,12 @@ pub trait Enumerable: Iterator { } /// Concatenates two sequences. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// let x = 0..100; /// let y = 100..200; /// let e = x.concate(y); @@ -186,12 +186,12 @@ pub trait Enumerable: Iterator { } /// Returns the first element of a sequence. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// assert!((0..0).first().is_none()); /// assert_eq!((0..2).first(), Some(0)); /// assert_eq!((0..1).first(), Some(0)); @@ -204,14 +204,14 @@ pub trait Enumerable: Iterator { } /// Returns the index-th element of the iterator. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// let a = [1, 2, 3]; - /// + /// /// assert_eq!(a.iter().element_at(0), Some(&1)); /// assert_eq!(a.iter().element_at(1), Some(&2)); /// assert_eq!(a.iter().element_at(2), Some(&3)); @@ -225,12 +225,12 @@ pub trait Enumerable: Iterator { } /// Returns the only element of a sequence. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// assert!((0..0).single().is_none()); /// assert!((0..2).single().is_none()); /// assert_eq!((0..1).single(), Some(0)); @@ -243,19 +243,19 @@ pub trait Enumerable: Iterator { } /// Inverts the order of the elements in a sequence. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// let a = [1, 2, 3]; /// let mut iter = a.iter().reverse(); - /// + /// /// assert_eq!(iter.next(), Some(&3)); /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), Some(&1)); - /// + /// /// assert_eq!(iter.next(), None); /// ``` fn reverse(self) -> ReverseIterator @@ -266,12 +266,12 @@ pub trait Enumerable: Iterator { } /// Determines whether a sequence contains a specified element by using the default equality comparer. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// let x = 0..10; /// assert!(x.clone().contains(&0)); /// assert!(x.clone().contains(&5)); @@ -286,12 +286,12 @@ pub trait Enumerable: Iterator { } /// Applies an accumulator function over a sequence. The specified seed value is used as the initial accumulator value. - /// + /// /// # Examples - /// + /// /// ``` /// use linq::iter::Enumerable; - /// + /// /// let x = 0..10; /// assert_eq!(x.clone().aggregate(1, |b, v| b * v), x.clone().product()); /// ``` @@ -311,7 +311,7 @@ pub trait Enumerable: Iterator { m_distinct::distinct(self) } - fn union(self, union_with : U) -> m_union::UnionIterator + fn union(self, union_with: U) -> m_union::UnionIterator where Self: Sized, Self::Item: Eq + std::hash::Hash + Copy, @@ -319,7 +319,14 @@ pub trait Enumerable: Iterator { { m_union::union(self, union_with) } - + + fn average(self) -> A + where + Self: Sized, + A: Average, + { + Average::average(self) + } } impl Enumerable for I where I: Iterator {} diff --git a/src/iter/m_union.rs b/src/iter/m_union.rs index ce8c804..bbd006c 100644 --- a/src/iter/m_union.rs +++ b/src/iter/m_union.rs @@ -1,32 +1,30 @@ #[derive(Clone)] pub struct UnionIterator where - I::Item : Eq + std::hash::Hash + Copy, - I : Iterator, - U : Iterator, + I::Item: Eq + std::hash::Hash + Copy, + I: Iterator, + U: Iterator, { - first_source : I, - second_source : U, - was_first_source_consumed : bool, - hash_map : std::collections::HashSet + first_source: I, + second_source: U, + was_first_source_consumed: bool, + hash_map: std::collections::HashSet, } impl Iterator for UnionIterator where - I : Iterator, - U : Iterator, - I::Item : Eq + std::hash::Hash + Copy, + I: Iterator, + U: Iterator, + I::Item: Eq + std::hash::Hash + Copy, { type Item = I::Item; fn next(&mut self) -> Option { loop { - if !self.was_first_source_consumed - { + if !self.was_first_source_consumed { match self.first_source.next() { Some(item) => { - if self.hash_map.insert(item) - { + if self.hash_map.insert(item) { return Some(item); } } @@ -37,8 +35,7 @@ where } match self.second_source.next() { Some(item) => { - if self.hash_map.insert(item) - { + if self.hash_map.insert(item) { return Some(item); } } @@ -50,21 +47,17 @@ where } } - -pub fn union( - iter: I, - iter_union : U -) -> UnionIterator +pub fn union(iter: I, iter_union: U) -> UnionIterator where - I : Iterator, - U : Iterator, - I::Item : Eq + std::hash::Hash + Copy, + I: Iterator, + U: Iterator, + I::Item: Eq + std::hash::Hash + Copy, { let hash_map = std::collections::HashSet::new(); UnionIterator { - hash_map : hash_map, - first_source : iter, - second_source : iter_union, - was_first_source_consumed : false + hash_map: hash_map, + first_source: iter, + second_source: iter_union, + was_first_source_consumed: false, } } diff --git a/src/iter/mod.rs b/src/iter/mod.rs index eede593..37cae4e 100644 --- a/src/iter/mod.rs +++ b/src/iter/mod.rs @@ -1,11 +1,12 @@ //! Provide the implement of LINQ to Objects, based on `Iterator`. +mod average; +mod m_builtin; +mod m_distinct; mod m_enumerable; +mod m_method; mod m_order_by; mod m_select; -mod m_builtin; -mod m_method; -mod m_distinct; mod m_union; pub use m_enumerable::*; diff --git a/src/lib.rs b/src/lib.rs index aab13bc..e0e13fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,4 +96,4 @@ macro_rules! linq { } #[cfg(test)] -mod tests; \ No newline at end of file +mod tests; diff --git a/src/tests/iter_expr.rs b/src/tests/iter_expr.rs index dd30f87..b29c250 100644 --- a/src/tests/iter_expr.rs +++ b/src/tests/iter_expr.rs @@ -86,6 +86,8 @@ fn where_order() { fn distinct() { let x = [1, 2, 4, 2, 5, 6]; let y: Vec = x.iter().distinct().cloned().collect(); - let e: Vec = linq!(from p in x.iter(), select distinct p).cloned().collect(); + let e: Vec = linq!(from p in x.iter(), select distinct p) + .cloned() + .collect(); assert_eq!(e, y); -} \ No newline at end of file +} diff --git a/src/tests/iter_methods.rs b/src/tests/iter_methods.rs index 22ef523..72a41dd 100644 --- a/src/tests/iter_methods.rs +++ b/src/tests/iter_methods.rs @@ -9,6 +9,15 @@ fn select() { assert_eq!(e, y); } +#[test] +fn average() { + let int_avg: i32 = (1..100).select(|p| p * 2).average(); + assert_eq!(int_avg, 100); + + let float_avg: f64 = (1..50).select(|p| (p as f64) / 2f64).average(); + assert_eq!(float_avg, 12.5); +} + #[test] fn select_many() { let x = 1..5; @@ -145,7 +154,7 @@ fn element_at() { #[test] fn distict() { let a = [1, 2, 3, 2, 3, 5]; - let mut iter = a.iter().distinct(); + let mut iter = a.iter().distinct(); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&3)); @@ -158,7 +167,7 @@ fn distict() { fn union() { let a = [1, 2, 3, 2, 3, 4]; let b = [1, 2, 2, 5, 3, 6]; - let mut iter = a.iter().union(b.iter()); + let mut iter = a.iter().union(b.iter()); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&3)); @@ -167,4 +176,4 @@ fn union() { assert_eq!(iter.next(), Some(&6)); assert_eq!(iter.next(), None); -} \ No newline at end of file +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 1945444..d6309e0 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,3 @@ #[cfg(test)] - pub mod iter_expr; -pub mod iter_methods; \ No newline at end of file +pub mod iter_methods; diff --git a/tests/int_test.rs b/tests/int_test.rs index e20a4ec..378eb67 100644 --- a/tests/int_test.rs +++ b/tests/int_test.rs @@ -1,6 +1,5 @@ -use linq::linq; use linq::iter::Enumerable; - +use linq::linq; #[test] fn try_linq() {