diff --git a/asparit/src/core/iterator.rs b/asparit/src/core/iterator.rs index 527908f..c77bdcd 100644 --- a/asparit/src/core/iterator.rs +++ b/asparit/src/core/iterator.rs @@ -1,3 +1,4 @@ +use std::cmp::{Ord, Ordering}; use std::iter::IntoIterator; use super::{ @@ -19,6 +20,7 @@ use crate::{ map::Map, map_init::MapInit, map_with::MapWith, + min::{Min, MinBy}, product::Product, reduce::{Reduce, ReduceWith}, sum::Sum, @@ -1083,6 +1085,60 @@ pub trait ParallelIterator<'a>: Sized + Send { Product::new(self) } + /// Computes the minimum of all the items in the iterator. If the + /// iterator is empty, `None` is returned; otherwise, `Some(min)` + /// is returned. + /// + /// Note that the order in which the items will be reduced is not + /// specified, so if the `Ord` impl is not truly associative, then + /// the results are not deterministic. + /// + /// Basically equivalent to `self.reduce_with(|a, b| cmp::min(a, b))`. + /// + /// # Examples + /// + /// ``` + /// use rayon::prelude::*; + /// + /// let a = [45, 74, 32]; + /// + /// assert_eq!(a.par_iter().min(), Some(&32)); + /// + /// let b: [i32; 0] = []; + /// + /// assert_eq!(b.par_iter().min(), None); + /// ``` + fn min(self) -> Min + where + Self::Item: Ord, + { + Min::new(self) + } + + /// Computes the minimum of all the items in the iterator with respect to + /// the given comparison function. If the iterator is empty, `None` is + /// returned; otherwise, `Some(min)` is returned. + /// + /// Note that the order in which the items will be reduced is not + /// specified, so if the comparison function is not associative, then + /// the results are not deterministic. + /// + /// # Examples + /// + /// ``` + /// use rayon::prelude::*; + /// + /// let a = [-3_i32, 77, 53, 240, -1]; + /// + /// assert_eq!(a.par_iter().min_by(|x, y| x.cmp(y)), Some(&-3)); + /// ``` + fn min_by(self, operation: O) -> MinBy + where + O: Fn(&Self::Item, &Self::Item) -> Ordering + Clone + Send + Sync + 'a, + { + MinBy::new(self, operation) + } + /// Creates a fresh collection containing all the elements produced /// by this parallel iterator. /// diff --git a/asparit/src/inner/min.rs b/asparit/src/inner/min.rs new file mode 100644 index 0000000..61759c2 --- /dev/null +++ b/asparit/src/inner/min.rs @@ -0,0 +1,65 @@ +use std::cmp::{min, Ord, Ordering}; + +use crate::{Driver, Executor, ParallelIterator}; + +/* Min */ + +pub struct Min { + iterator: X, +} + +impl Min { + pub fn new(iterator: X) -> Self { + Self { iterator } + } +} + +impl<'a, X, T> Driver<'a, Option> for Min +where + X: ParallelIterator<'a, Item = T>, + T: Send + Ord + 'a, +{ + fn exec_with(self, executor: E) -> E::Result + where + E: Executor<'a, Option>, + { + self.iterator.reduce_with(min).exec_with(executor) + } +} + +/* MinBy */ + +pub struct MinBy { + iterator: X, + operation: O, +} + +impl MinBy { + pub fn new(iterator: X, operation: O) -> Self { + Self { + iterator, + operation, + } + } +} + +impl<'a, X, O, T> Driver<'a, Option> for MinBy +where + X: ParallelIterator<'a, Item = T>, + O: Fn(&T, &T) -> Ordering + Clone + Send + Sync + 'a, + T: Send + Ord + 'a, +{ + fn exec_with(self, executor: E) -> E::Result + where + E: Executor<'a, Option>, + { + let operation = self.operation; + + self.iterator + .reduce_with(move |a, b| match operation(&a, &b) { + Ordering::Greater => b, + _ => a, + }) + .exec_with(executor) + } +} diff --git a/asparit/src/inner/mod.rs b/asparit/src/inner/mod.rs index 897fcdf..5ffc150 100644 --- a/asparit/src/inner/mod.rs +++ b/asparit/src/inner/mod.rs @@ -11,6 +11,7 @@ pub mod inspect; pub mod map; pub mod map_init; pub mod map_with; +pub mod min; pub mod noop; pub mod product; pub mod reduce;