Skip to content

Commit

Permalink
Add Itertools::filter_map_results
Browse files Browse the repository at this point in the history
  • Loading branch information
gin-ahirsch committed Oct 29, 2019
1 parent b5ccfe0 commit cad46e7
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/adaptors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,71 @@ impl<I, F, T, E> Iterator for FilterResults<I, F>
}
}

/// An iterator adapter to filter and apply a transformation on values within a nested `Result`.
///
/// See [`.filter_map_results()`](../trait.Itertools.html#method.filter_map_results) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FilterMapResults<I, F> {
iter: I,
f: F
}

/// Create a new `FilterResults` iterator.
pub fn filter_map_results<I, F, T, U, E>(iter: I, f: F) -> FilterMapResults<I, F>
where I: Iterator<Item = Result<T, E>>,
F: FnMut(T) -> Option<U>,
{
FilterMapResults {
iter: iter,
f: f,
}
}

impl<I, F, T, U, E> Iterator for FilterMapResults<I, F>
where I: Iterator<Item = Result<T, E>>,
F: FnMut(T) -> Option<U>,
{
type Item = Result<U, E>;

fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next() {
Some(Ok(v)) => {
if let Some(v) = (self.f)(v) {
return Some(Ok(v));
}
},
Some(Err(e)) => return Some(Err(e)),
None => return None,
}
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
where Fold: FnMut(Acc, Self::Item) -> Acc,
{
let mut f = self.f;
self.iter.fold(init, move |acc, v| {
if let Some(v) = v.map(&mut f).transpose() {
fold_f(acc, v)
} else {
acc
}
})
}

fn collect<C>(self) -> C
where C: FromIterator<Self::Item>
{
let mut f = self.f;
self.iter.filter_map(move |v| v.map(&mut f).transpose()).collect()
}
}

/// An iterator adapter to get the positions of each element that matches a predicate.
///
/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub mod structs {
DedupBy,
Interleave,
InterleaveShortest,
FilterMapResults,
FilterResults,
Product,
PutBack,
Expand Down Expand Up @@ -731,6 +732,24 @@ pub trait Itertools : Iterator {
adaptors::filter_results(self, f)
}

/// Return an iterator adaptor that filters and transforms every
/// `Result::Ok` value with the provided closure. `Result::Err`
/// values are unchanged.
///
/// ```
/// use itertools::Itertools;
///
/// let input = vec![Ok(22), Err(false), Ok(11)];
/// let it = input.into_iter().filter_map_results(|i| if i > 20 { Some(i * 2) } else { None });
/// itertools::assert_equal(it, vec![Ok(44), Err(false)]);
/// ```
fn filter_map_results<F, T, U, E>(self, f: F) -> FilterMapResults<Self, F>
where Self: Iterator<Item = Result<T, E>> + Sized,
F: FnMut(T) -> Option<U>,
{
adaptors::filter_map_results(self, f)
}

/// Return an iterator adaptor that merges the two base iterators in
/// ascending order. If both base iterators are sorted (ascending), the
/// result is sorted.
Expand Down

0 comments on commit cad46e7

Please sign in to comment.