Skip to content

Commit

Permalink
Add average functionality (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
RohanPoojary authored Jun 27, 2023
1 parent 1dea704 commit 5ee750c
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 84 deletions.
18 changes: 18 additions & 0 deletions src/iter/average.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pub trait Average<A = Self>: Sized {
fn average<I: Iterator<Item = A>>(iter: I) -> Self;
}

macro_rules! average_for_types {
( $( $x:ident ),* ) => {$(
impl Average for $x {
fn average<I: Iterator<Item = Self>>(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);
28 changes: 12 additions & 16 deletions src/iter/m_distinct.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
#[derive(Clone)]
pub struct DistinctIterator<I>
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<I::Item>
source: I,
hash_map: std::collections::HashSet<I::Item>,
}

impl<I> Iterator for DistinctIterator<I>
where
I : Iterator,
I::Item : Eq + std::hash::Hash + Copy,
I: Iterator,
I::Item: Eq + std::hash::Hash + Copy,
{
type Item = I::Item;

fn next(&mut self) -> Option<Self::Item> {
loop {
match self.source.next() {
Some(item) => {
if self.hash_map.insert(item)
{
if self.hash_map.insert(item) {
return Some(item);
}
}
Expand All @@ -32,17 +31,14 @@ where
}
}


pub fn distinct<I>(
iter: I
) -> DistinctIterator<I>
pub fn distinct<I>(iter: I) -> DistinctIterator<I>
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,
}
}
61 changes: 34 additions & 27 deletions src/iter/m_enumerable.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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<Self>
Expand All @@ -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));
Expand All @@ -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());
/// ```
Expand All @@ -311,15 +311,22 @@ pub trait Enumerable: Iterator {
m_distinct::distinct(self)
}

fn union<U>(self, union_with : U) -> m_union::UnionIterator<Self, U>
fn union<U>(self, union_with: U) -> m_union::UnionIterator<Self, U>
where
Self: Sized,
Self::Item: Eq + std::hash::Hash + Copy,
U: Enumerable<Item = Self::Item>,
{
m_union::union(self, union_with)
}


fn average<A>(self) -> A
where
Self: Sized,
A: Average<Self::Item>,
{
Average::average(self)
}
}

impl<I, T> Enumerable for I where I: Iterator<Item = T> {}
49 changes: 21 additions & 28 deletions src/iter/m_union.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
#[derive(Clone)]
pub struct UnionIterator<I, U>
where
I::Item : Eq + std::hash::Hash + Copy,
I : Iterator,
U : Iterator<Item=I::Item>,
I::Item: Eq + std::hash::Hash + Copy,
I: Iterator,
U: Iterator<Item = I::Item>,
{
first_source : I,
second_source : U,
was_first_source_consumed : bool,
hash_map : std::collections::HashSet<I::Item>
first_source: I,
second_source: U,
was_first_source_consumed: bool,
hash_map: std::collections::HashSet<I::Item>,
}

impl<I, U> Iterator for UnionIterator<I, U>
where
I : Iterator,
U : Iterator<Item=I::Item>,
I::Item : Eq + std::hash::Hash + Copy,
I: Iterator,
U: Iterator<Item = I::Item>,
I::Item: Eq + std::hash::Hash + Copy,
{
type Item = I::Item;

fn next(&mut self) -> Option<Self::Item> {
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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -50,21 +47,17 @@ where
}
}


pub fn union<I, U>(
iter: I,
iter_union : U
) -> UnionIterator<I, U>
pub fn union<I, U>(iter: I, iter_union: U) -> UnionIterator<I, U>
where
I : Iterator,
U : Iterator<Item=I::Item>,
I::Item : Eq + std::hash::Hash + Copy,
I: Iterator,
U: Iterator<Item = I::Item>,
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,
}
}
7 changes: 4 additions & 3 deletions src/iter/mod.rs
Original file line number Diff line number Diff line change
@@ -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::*;
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ macro_rules! linq {
}

#[cfg(test)]
mod tests;
mod tests;
6 changes: 4 additions & 2 deletions src/tests/iter_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ fn where_order() {
fn distinct() {
let x = [1, 2, 4, 2, 5, 6];
let y: Vec<i32> = x.iter().distinct().cloned().collect();
let e: Vec<i32> = linq!(from p in x.iter(), select distinct p).cloned().collect();
let e: Vec<i32> = linq!(from p in x.iter(), select distinct p)
.cloned()
.collect();
assert_eq!(e, y);
}
}
15 changes: 12 additions & 3 deletions src/tests/iter_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand All @@ -167,4 +176,4 @@ fn union() {
assert_eq!(iter.next(), Some(&6));

assert_eq!(iter.next(), None);
}
}
3 changes: 1 addition & 2 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#[cfg(test)]

pub mod iter_expr;
pub mod iter_methods;
pub mod iter_methods;
Loading

0 comments on commit 5ee750c

Please sign in to comment.