Skip to content

Commit 3014ebf

Browse files
committed
Add Itertools::filter_map_results
1 parent 195dd1a commit 3014ebf

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/adaptors/mod.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,72 @@ impl<I, F, T, E> Iterator for FilterResults<I, F>
11921192
}
11931193
}
11941194

1195+
/// An iterator adapter to filter and apply a transformation on values within a nested `Result`.
1196+
///
1197+
/// See [`.filter_map_results()`](../trait.Itertools.html#method.filter_map_results) for more information.
1198+
#[derive(Clone)]
1199+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1200+
pub struct FilterMapResults<I, F> {
1201+
iter: I,
1202+
f: F
1203+
}
1204+
1205+
/// Create a new `FilterResults` iterator.
1206+
pub fn filter_map_results<I, F, T, U, E>(iter: I, f: F) -> FilterMapResults<I, F>
1207+
where I: Iterator<Item = Result<T, E>>,
1208+
F: FnMut(T) -> Option<U>,
1209+
{
1210+
FilterMapResults {
1211+
iter,
1212+
f,
1213+
}
1214+
}
1215+
1216+
impl<I, F, T, U, E> Iterator for FilterMapResults<I, F>
1217+
where I: Iterator<Item = Result<T, E>>,
1218+
F: FnMut(T) -> Option<U>,
1219+
{
1220+
type Item = Result<U, E>;
1221+
1222+
fn next(&mut self) -> Option<Self::Item> {
1223+
loop {
1224+
match self.iter.next() {
1225+
Some(Ok(v)) => {
1226+
if let Some(v) = (self.f)(v) {
1227+
return Some(Ok(v));
1228+
}
1229+
},
1230+
Some(Err(e)) => return Some(Err(e)),
1231+
None => return None,
1232+
}
1233+
}
1234+
}
1235+
1236+
fn size_hint(&self) -> (usize, Option<usize>) {
1237+
(0, self.iter.size_hint().1)
1238+
}
1239+
1240+
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
1241+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1242+
{
1243+
let mut f = self.f;
1244+
self.iter.fold(init, move |acc, v| {
1245+
if let Some(v) = v.map(&mut f).transpose() {
1246+
fold_f(acc, v)
1247+
} else {
1248+
acc
1249+
}
1250+
})
1251+
}
1252+
1253+
fn collect<C>(self) -> C
1254+
where C: FromIterator<Self::Item>
1255+
{
1256+
let mut f = self.f;
1257+
self.iter.filter_map(move |v| v.map(&mut f).transpose()).collect()
1258+
}
1259+
}
1260+
11951261
/// An iterator adapter to get the positions of each element that matches a predicate.
11961262
///
11971263
/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.

src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub mod structs {
8080
DedupBy,
8181
Interleave,
8282
InterleaveShortest,
83+
FilterMapResults,
8384
FilterResults,
8485
Product,
8586
PutBack,
@@ -756,6 +757,24 @@ pub trait Itertools : Iterator {
756757
adaptors::filter_results(self, f)
757758
}
758759

760+
/// Return an iterator adaptor that filters and transforms every
761+
/// `Result::Ok` value with the provided closure. `Result::Err`
762+
/// values are unchanged.
763+
///
764+
/// ```
765+
/// use itertools::Itertools;
766+
///
767+
/// let input = vec![Ok(22), Err(false), Ok(11)];
768+
/// let it = input.into_iter().filter_map_results(|i| if i > 20 { Some(i * 2) } else { None });
769+
/// itertools::assert_equal(it, vec![Ok(44), Err(false)]);
770+
/// ```
771+
fn filter_map_results<F, T, U, E>(self, f: F) -> FilterMapResults<Self, F>
772+
where Self: Iterator<Item = Result<T, E>> + Sized,
773+
F: FnMut(T) -> Option<U>,
774+
{
775+
adaptors::filter_map_results(self, f)
776+
}
777+
759778
/// Return an iterator adaptor that merges the two base iterators in
760779
/// ascending order. If both base iterators are sorted (ascending), the
761780
/// result is sorted.

0 commit comments

Comments
 (0)