Skip to content

Commit 195dd1a

Browse files
committed
Add Itertools::filter_results
1 parent 2c6b6ed commit 195dd1a

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/adaptors/mod.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,74 @@ impl<I, F, T, U, E> Iterator for MapResults<I, F>
11241124
}
11251125
}
11261126

1127+
/// An iterator adapter to filter values within a nested `Result`.
1128+
///
1129+
/// See [`.filter_results()`](../trait.Itertools.html#method.filter_results) for more information.
1130+
#[derive(Clone)]
1131+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1132+
pub struct FilterResults<I, F> {
1133+
iter: I,
1134+
f: F
1135+
}
1136+
1137+
/// Create a new `FilterResults` iterator.
1138+
pub fn filter_results<I, F, T, E>(iter: I, f: F) -> FilterResults<I, F>
1139+
where I: Iterator<Item = Result<T, E>>,
1140+
F: FnMut(&T) -> bool,
1141+
{
1142+
FilterResults {
1143+
iter,
1144+
f,
1145+
}
1146+
}
1147+
1148+
impl<I, F, T, E> Iterator for FilterResults<I, F>
1149+
where I: Iterator<Item = Result<T, E>>,
1150+
F: FnMut(&T) -> bool,
1151+
{
1152+
type Item = Result<T, E>;
1153+
1154+
fn next(&mut self) -> Option<Self::Item> {
1155+
loop {
1156+
match self.iter.next() {
1157+
Some(Ok(v)) => {
1158+
if (self.f)(&v) {
1159+
return Some(Ok(v));
1160+
}
1161+
},
1162+
Some(Err(e)) => return Some(Err(e)),
1163+
None => return None,
1164+
}
1165+
}
1166+
}
1167+
1168+
fn size_hint(&self) -> (usize, Option<usize>) {
1169+
(0, self.iter.size_hint().1)
1170+
}
1171+
1172+
fn fold<Acc, Fold>(self, init: Acc, mut fold_f: Fold) -> Acc
1173+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1174+
{
1175+
let mut f = self.f;
1176+
self.iter.fold(init, move |acc, v| {
1177+
if v.as_ref().map(&mut f).unwrap_or(true) {
1178+
fold_f(acc, v)
1179+
} else {
1180+
acc
1181+
}
1182+
})
1183+
}
1184+
1185+
fn collect<C>(self) -> C
1186+
where C: FromIterator<Self::Item>
1187+
{
1188+
let mut f = self.f;
1189+
self.iter.filter(move |v| {
1190+
v.as_ref().map(&mut f).unwrap_or(true)
1191+
}).collect()
1192+
}
1193+
}
1194+
11271195
/// An iterator adapter to get the positions of each element that matches a predicate.
11281196
///
11291197
/// 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+
FilterResults,
8384
Product,
8485
PutBack,
8586
Batching,
@@ -737,6 +738,24 @@ pub trait Itertools : Iterator {
737738
adaptors::map_results(self, f)
738739
}
739740

741+
/// Return an iterator adaptor that filters every `Result::Ok`
742+
/// value with the provided closure. `Result::Err` values are
743+
/// unchanged.
744+
///
745+
/// ```
746+
/// use itertools::Itertools;
747+
///
748+
/// let input = vec![Ok(22), Err(false), Ok(11)];
749+
/// let it = input.into_iter().filter_results(|&i| i > 20);
750+
/// itertools::assert_equal(it, vec![Ok(22), Err(false)]);
751+
/// ```
752+
fn filter_results<F, T, E>(self, f: F) -> FilterResults<Self, F>
753+
where Self: Iterator<Item = Result<T, E>> + Sized,
754+
F: FnMut(&T) -> bool,
755+
{
756+
adaptors::filter_results(self, f)
757+
}
758+
740759
/// Return an iterator adaptor that merges the two base iterators in
741760
/// ascending order. If both base iterators are sorted (ascending), the
742761
/// result is sorted.

0 commit comments

Comments
 (0)