Skip to content

Commit

Permalink
Added distinct LINQ (#2)
Browse files Browse the repository at this point in the history
* Added distinct LINQ

* Added Union method

* Updated README.md
  • Loading branch information
sandrohanea authored Jul 24, 2020
1 parent 478c783 commit 1dea704
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ The trait `linq::Queryable` supports LINQ methods on `Iterator`. You can find th
- [ ] *then_by_descending*
- [x] **reverse** => rev
- [ ] *group_by*
- [ ] *distinct*
- [ ] *union*
- [x] distinct
- [x] union
- [ ] *intersect*
- [ ] *except*
- [x] **first** => next
Expand Down
48 changes: 48 additions & 0 deletions src/iter/m_distinct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#[derive(Clone)]
pub struct DistinctIterator<I>
where
I::Item : Eq + std::hash::Hash + Copy,
I : Iterator
{
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,
{
type Item = I::Item;

fn next(&mut self) -> Option<Self::Item> {
loop {
match self.source.next() {
Some(item) => {
if self.hash_map.insert(item)
{
return Some(item);
}
}
None => {
return None;
}
}
}
}
}


pub fn distinct<I>(
iter: I
) -> DistinctIterator<I>
where
I : Iterator,
I::Item : Eq + std::hash::Hash + Copy,
{
let hash_map = std::collections::HashSet::new();
DistinctIterator {
hash_map : hash_map,
source : iter
}
}
20 changes: 19 additions & 1 deletion 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};
use super::{m_builtin, m_method, m_order_by, m_select, m_distinct, m_union};
use m_builtin::{ConcateIterator, ReverseIterator, SelectIterator, WhereIterator};
use m_order_by::OrderedIterator;
use m_select::{SelectManyIterator, SelectManySingleIterator};
Expand Down Expand Up @@ -302,6 +302,24 @@ pub trait Enumerable: Iterator {
{
m_builtin::aggregate(self, init, f)
}

fn distinct(self) -> m_distinct::DistinctIterator<Self>
where
Self: Sized,
Self::Item: Eq + std::hash::Hash + Copy,
{
m_distinct::distinct(self)
}

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)
}

}

impl<I, T> Enumerable for I where I: Iterator<Item = T> {}
70 changes: 70 additions & 0 deletions src/iter/m_union.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#[derive(Clone)]
pub struct UnionIterator<I, U>
where
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>
}

impl<I, U> Iterator for UnionIterator<I, U>
where
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
{
match self.first_source.next() {
Some(item) => {
if self.hash_map.insert(item)
{
return Some(item);
}
}
None => {
self.was_first_source_consumed = true;
}
}
}
match self.second_source.next() {
Some(item) => {
if self.hash_map.insert(item)
{
return Some(item);
}
}
None => {
return None;
}
}
}
}
}


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,
{
let hash_map = std::collections::HashSet::new();
UnionIterator {
hash_map : hash_map,
first_source : iter,
second_source : iter_union,
was_first_source_consumed : false
}
}
2 changes: 2 additions & 0 deletions src/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ mod m_order_by;
mod m_select;
mod m_builtin;
mod m_method;
mod m_distinct;
mod m_union;

pub use m_enumerable::*;
32 changes: 32 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,66 @@ macro_rules! linq {
{
$c.select(|$v| $ms)
};
(from $v:ident in $c:expr, select distinct $ms:expr) =>
{
$c.select(|$v| $ms).distinct()
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ select $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).select(|$v| $ms)
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ select distinct $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).select(|$v| $ms).distinct()
};
(from $v:ident in $c:expr, orderby $mo:expr, select $ms:expr) =>
{
$c.order_by(|$v| $mo).select(|$v| $ms)
};
(from $v:ident in $c:expr, orderby $mo:expr, select distinct $ms:expr) =>
{
$c.order_by(|$v| $mo).select(|$v| $ms).distinct()
};
(from $v:ident in $c:expr, orderby $mo:expr, descending, select $ms:expr) =>
{
$c.order_by_descending(|$v| $mo).select(|$v| $ms)
};
(from $v:ident in $c:expr, orderby $mo:expr, descending, select distinct $ms:expr) =>
{
$c.order_by_descending(|$v| $mo).select(|$v| $ms).distinct()
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ orderby $mo:expr, select $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).order_by(|$v| $mo).select(|$v| $ms)
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ orderby $mo:expr, select distinct $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).order_by(|$v| $mo).select(|$v| $ms).distinct()
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ orderby $mo:expr, descending, select $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).order_by_descending(|$v| $mo).select(|$v| $ms)
};
(from $v:ident in $c:expr, $(where $mw:expr,)+ orderby $mo:expr, descending, select distinct $ms:expr) =>
{
$c.where_by(|$v| true $(&& $mw)+ ).order_by_descending(|$v| $mo).select(|$v| $ms).distinct()
};
(from $v0:ident in $c0:expr, from $v:ident in $c:expr, select $ms:expr) =>
{
$c0.select_many_single(|$v0| $c).select(|$v| $ms)
};
(from $v0:ident in $c0:expr, from $v:ident in $c:expr, select distinct $ms:expr) =>
{
$c0.select_many_single(|$v0| $c).select(|$v| $ms).distinct()
};
(from $v0:ident in $c0:expr, zfrom $v:ident in $c:expr, select $ms:expr) =>
{
$c0.select_many(|$v0| $c, |$v0, $v| $ms)
};
(from $v0:ident in $c0:expr, zfrom $v:ident in $c:expr, select distinct $ms:expr) =>
{
$c0.select_many(|$v0| $c, |$v0, $v| $ms).distinct()
};
}

#[cfg(test)]
Expand Down
8 changes: 8 additions & 0 deletions src/tests/iter_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,11 @@ fn where_order() {
let e: Vec<i32> = linq!(from p in x.clone(), where p <= &5, orderby -p, select p * 2).collect();
assert_eq!(e, y);
}

#[test]
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();
assert_eq!(e, y);
}
27 changes: 27 additions & 0 deletions src/tests/iter_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,31 @@ fn element_at() {
assert_eq!(a.iter().element_at(1), Some(&2));
assert_eq!(a.iter().element_at(2), Some(&3));
assert_eq!(a.iter().element_at(3), None);
}

#[test]
fn distict() {
let a = [1, 2, 3, 2, 3, 5];
let mut iter = a.iter().distinct();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), Some(&5));

assert_eq!(iter.next(), None);
}

#[test]
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());
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), Some(&4));
assert_eq!(iter.next(), Some(&5));
assert_eq!(iter.next(), Some(&6));

assert_eq!(iter.next(), None);
}

0 comments on commit 1dea704

Please sign in to comment.