Skip to content

Commit 636a332

Browse files
Merge #377 #381
377: Add Itertools::filter_{,map_}results r=jswrenn a=gin-ahirsch I found myself wanting `filter_map_results()` and just implemented `filter_results()` in the same stretch. I hope you find it useful! I wasn't sure if #236 applies to these new iterators; I just implemented them. 381: Add Itertools::intersperse_with r=jswrenn a=gin-ahirsch Pretty self-explanatory. Useful for non-clonable elements or otherwise stateful interspersing. `intersperse()` could be implemented via `intersperse_with()`, allowing the change to be more minimal. I haven't done it currently, but if you don't see any downsides I'd amend this change to do `self.intersperse_with(|| element)` for `intersperse()` instead. Co-authored-by: Alexander Hirsch <[email protected]>
3 parents a517cfc + 3890a93 + 22b1984 commit 636a332

File tree

3 files changed

+309
-18
lines changed

3 files changed

+309
-18
lines changed

src/adaptors/mod.rs

Lines changed: 145 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,28 +1086,31 @@ where
10861086
I::Item: Into<R>,
10871087
{}
10881088

1089-
/// An iterator adapter to apply a transformation within a nested `Result`.
1089+
#[deprecated(note="Use MapOk instead", since="0.10")]
1090+
pub type MapResults<I, F> = MapOk<I, F>;
1091+
1092+
/// An iterator adapter to apply a transformation within a nested `Result::Ok`.
10901093
///
1091-
/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information.
1094+
/// See [`.map_ok()`](../trait.Itertools.html#method.map_ok) for more information.
10921095
#[derive(Clone)]
10931096
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1094-
pub struct MapResults<I, F> {
1097+
pub struct MapOk<I, F> {
10951098
iter: I,
10961099
f: F
10971100
}
10981101

1099-
/// Create a new `MapResults` iterator.
1100-
pub fn map_results<I, F, T, U, E>(iter: I, f: F) -> MapResults<I, F>
1102+
/// Create a new `MapOk` iterator.
1103+
pub fn map_ok<I, F, T, U, E>(iter: I, f: F) -> MapOk<I, F>
11011104
where I: Iterator<Item = Result<T, E>>,
11021105
F: FnMut(T) -> U,
11031106
{
1104-
MapResults {
1107+
MapOk {
11051108
iter,
11061109
f,
11071110
}
11081111
}
11091112

1110-
impl<I, F, T, U, E> Iterator for MapResults<I, F>
1113+
impl<I, F, T, U, E> Iterator for MapOk<I, F>
11111114
where I: Iterator<Item = Result<T, E>>,
11121115
F: FnMut(T) -> U,
11131116
{
@@ -1136,6 +1139,141 @@ impl<I, F, T, U, E> Iterator for MapResults<I, F>
11361139
}
11371140
}
11381141

1142+
/// An iterator adapter to filter values within a nested `Result::Ok`.
1143+
///
1144+
/// See [`.filter_ok()`](../trait.Itertools.html#method.filter_ok) for more information.
1145+
#[derive(Clone)]
1146+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1147+
pub struct FilterOk<I, F> {
1148+
iter: I,
1149+
f: F
1150+
}
1151+
1152+
/// Create a new `FilterOk` iterator.
1153+
pub fn filter_ok<I, F, T, E>(iter: I, f: F) -> FilterOk<I, F>
1154+
where I: Iterator<Item = Result<T, E>>,
1155+
F: FnMut(&T) -> bool,
1156+
{
1157+
FilterOk {
1158+
iter,
1159+
f,
1160+
}
1161+
}
1162+
1163+
impl<I, F, T, E> Iterator for FilterOk<I, F>
1164+
where I: Iterator<Item = Result<T, E>>,
1165+
F: FnMut(&T) -> bool,
1166+
{
1167+
type Item = Result<T, E>;
1168+
1169+
fn next(&mut self) -> Option<Self::Item> {
1170+
loop {
1171+
match self.iter.next() {
1172+
Some(Ok(v)) => {
1173+
if (self.f)(&v) {
1174+
return Some(Ok(v));
1175+
}
1176+
},
1177+
Some(Err(e)) => return Some(Err(e)),
1178+
None => return None,
1179+
}
1180+
}
1181+
}
1182+
1183+
fn size_hint(&self) -> (usize, Option<usize>) {
1184+
(0, self.iter.size_hint().1)
1185+
}
1186+
1187+
fn fold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc
1188+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1189+
{
1190+
let mut f = self.f;
1191+
self.iter.filter(|v| {
1192+
v.as_ref().map(&mut f).unwrap_or(true)
1193+
}).fold(init, fold_f)
1194+
}
1195+
1196+
fn collect<C>(self) -> C
1197+
where C: FromIterator<Self::Item>
1198+
{
1199+
let mut f = self.f;
1200+
self.iter.filter(|v| {
1201+
v.as_ref().map(&mut f).unwrap_or(true)
1202+
}).collect()
1203+
}
1204+
}
1205+
1206+
/// An iterator adapter to filter and apply a transformation on values within a nested `Result::Ok`.
1207+
///
1208+
/// See [`.filter_map_ok()`](../trait.Itertools.html#method.filter_map_ok) for more information.
1209+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1210+
pub struct FilterMapOk<I, F> {
1211+
iter: I,
1212+
f: F
1213+
}
1214+
1215+
fn transpose_result<T, E>(result: Result<Option<T>, E>) -> Option<Result<T, E>> {
1216+
match result {
1217+
Ok(Some(v)) => Some(Ok(v)),
1218+
Ok(None) => None,
1219+
Err(e) => Some(Err(e)),
1220+
}
1221+
}
1222+
1223+
/// Create a new `FilterOk` iterator.
1224+
pub fn filter_map_ok<I, F, T, U, E>(iter: I, f: F) -> FilterMapOk<I, F>
1225+
where I: Iterator<Item = Result<T, E>>,
1226+
F: FnMut(T) -> Option<U>,
1227+
{
1228+
FilterMapOk {
1229+
iter,
1230+
f,
1231+
}
1232+
}
1233+
1234+
impl<I, F, T, U, E> Iterator for FilterMapOk<I, F>
1235+
where I: Iterator<Item = Result<T, E>>,
1236+
F: FnMut(T) -> Option<U>,
1237+
{
1238+
type Item = Result<U, E>;
1239+
1240+
fn next(&mut self) -> Option<Self::Item> {
1241+
loop {
1242+
match self.iter.next() {
1243+
Some(Ok(v)) => {
1244+
if let Some(v) = (self.f)(v) {
1245+
return Some(Ok(v));
1246+
}
1247+
},
1248+
Some(Err(e)) => return Some(Err(e)),
1249+
None => return None,
1250+
}
1251+
}
1252+
}
1253+
1254+
fn size_hint(&self) -> (usize, Option<usize>) {
1255+
(0, self.iter.size_hint().1)
1256+
}
1257+
1258+
fn fold<Acc, Fold>(self, init: Acc, fold_f: Fold) -> Acc
1259+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1260+
{
1261+
let mut f = self.f;
1262+
self.iter.filter_map(|v| {
1263+
transpose_result(v.map(&mut f))
1264+
}).fold(init, fold_f)
1265+
}
1266+
1267+
fn collect<C>(self) -> C
1268+
where C: FromIterator<Self::Item>
1269+
{
1270+
let mut f = self.f;
1271+
self.iter.filter_map(|v| {
1272+
transpose_result(v.map(&mut f))
1273+
}).collect()
1274+
}
1275+
}
1276+
11391277
/// An iterator adapter to get the positions of each element that matches a predicate.
11401278
///
11411279
/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information.

src/intersperse.rs

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::iter::Fuse;
22
use super::size_hint;
33

4-
#[derive(Clone)]
54
/// An iterator adaptor to insert a particular value
65
/// between each element of the adapted iterator.
76
///
@@ -11,7 +10,7 @@ use super::size_hint;
1110
///
1211
/// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information.
1312
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
14-
#[derive(Debug)]
13+
#[derive(Clone, Debug)]
1514
pub struct Intersperse<I>
1615
where I: Iterator
1716
{
@@ -62,7 +61,7 @@ impl<I> Iterator for Intersperse<I>
6261
Self: Sized, F: FnMut(B, Self::Item) -> B,
6362
{
6463
let mut accum = init;
65-
64+
6665
if let Some(x) = self.peek.take() {
6766
accum = f(accum, x);
6867
}
@@ -77,3 +76,81 @@ impl<I> Iterator for Intersperse<I>
7776
})
7877
}
7978
}
79+
80+
/// An iterator adaptor to insert a particular value created by a function
81+
/// between each element of the adapted iterator.
82+
///
83+
/// Iterator element type is `I::Item`
84+
///
85+
/// This iterator is *fused*.
86+
///
87+
/// See [`.intersperse_with()`](../trait.Itertools.html#method.intersperse_with) for more information.
88+
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
89+
#[derive(Clone, Debug)]
90+
pub struct IntersperseWith<I, ElemF>
91+
where I: Iterator,
92+
ElemF: FnMut() -> I::Item,
93+
{
94+
element: ElemF,
95+
iter: Fuse<I>,
96+
peek: Option<I::Item>,
97+
}
98+
99+
/// Create a new IntersperseWith iterator
100+
pub fn intersperse_with<I, ElemF>(iter: I, elt: ElemF) -> IntersperseWith<I, ElemF>
101+
where I: Iterator,
102+
ElemF: FnMut() -> I::Item
103+
{
104+
let mut iter = iter.fuse();
105+
IntersperseWith {
106+
peek: iter.next(),
107+
iter: iter,
108+
element: elt,
109+
}
110+
}
111+
112+
impl<I, ElemF> Iterator for IntersperseWith<I, ElemF>
113+
where I: Iterator,
114+
ElemF: FnMut() -> I::Item
115+
{
116+
type Item = I::Item;
117+
#[inline]
118+
fn next(&mut self) -> Option<I::Item> {
119+
if self.peek.is_some() {
120+
self.peek.take()
121+
} else {
122+
self.peek = self.iter.next();
123+
if self.peek.is_some() {
124+
Some((self.element)())
125+
} else {
126+
None
127+
}
128+
}
129+
}
130+
131+
fn size_hint(&self) -> (usize, Option<usize>) {
132+
// 2 * SH + { 1 or 0 }
133+
let has_peek = self.peek.is_some() as usize;
134+
let sh = self.iter.size_hint();
135+
size_hint::add_scalar(size_hint::add(sh, sh), has_peek)
136+
}
137+
138+
fn fold<B, F>(mut self, init: B, mut f: F) -> B where
139+
Self: Sized, F: FnMut(B, Self::Item) -> B,
140+
{
141+
let mut accum = init;
142+
143+
if let Some(x) = self.peek.take() {
144+
accum = f(accum, x);
145+
}
146+
147+
let element = &mut self.element;
148+
149+
self.iter.fold(accum,
150+
|accum, x| {
151+
let accum = f(accum, (element)());
152+
let accum = f(accum, x);
153+
accum
154+
})
155+
}
156+
}

0 commit comments

Comments
 (0)